pub_sub_model_sync 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ba16c2e3129caa85cf184030955e6a1de130b23b9b552a620c1354234eb5376
4
- data.tar.gz: a4b3eb7514efe123a38fb46ed933bf9ac0b1f418f1675d73b13e2cee25e6fe03
3
+ metadata.gz: 3016ebc69eba9ccb8b168734db1b947b77a4c9400f48d8228f979a7c1ec9eab8
4
+ data.tar.gz: 82187606c0411ece3eb0d78db59a8794019e80acd5374ffd92b95b0eee4368f7
5
5
  SHA512:
6
- metadata.gz: b55d2b5f1bdd763061e0c2ea60f9fe080bdb1db26e5cdb20adf33973524612d2041b0c4dab1ec1afc90e4f7a91ea8327b41ef8c9ecf53ba8bafe543b92dd74e9
7
- data.tar.gz: 218f2d41a1fcb04d240a4c3e91daa58b989555f9a97dc488fbc0bd627c0db412e3de224afc31a02c73bfa123f8817705811da1f3e7d20d240036f00de4ccb11d
6
+ metadata.gz: f4335695f26d69f091a2ea1726221aab4b07b712827318adfe16f2d1275cde21a0860ce7562ed266f6a0661eb2b8d634abea0956a4478ad55f70e6c199c8a364
7
+ data.tar.gz: 9252e45ab27b332d9b50afc93da62a0a039c707a1bb3b219ff4e60c1c4f3dae8eb7a85024fc3d1dab87c006e448e60cf3d1f3d953dad8cc8fced24bd375b47cd
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ # 0.2.3 (April 15, 2020)
4
+ - Improve helper names
5
+ - feat: perform manual sync with custom settings
6
+ - fix for "IO timeout when reading 7 bytes" error (Rabbit)
7
+ - style: do not print processed message when failed
8
+ - feat: retry delivery message when failed (RabbitMQ)
9
+
10
+
3
11
  # 0.2.2 (March 27, 2020)
4
12
  - fix default value for cattr_accessor in ror < 5.2
5
13
  - add callbacks when publishing a message
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pub_sub_model_sync (0.2.2)
4
+ pub_sub_model_sync (0.2.3)
5
5
  activesupport
6
6
  rails
7
7
 
data/README.md CHANGED
@@ -97,9 +97,13 @@ class User < ActiveRecord::Base
97
97
  include PubSubModelSync::PublisherConcern
98
98
  ps_publish(%i[name:full_name email], actions: %i[update], as_klass: 'Client', id: :client_id)
99
99
 
100
- def ps_skip_for?(_action)
100
+ def ps_skip_callback?(_action)
101
101
  false # here logic with action to skip push message
102
102
  end
103
+
104
+ def ps_skip_sync?(_action)
105
+ false # here logic with action to skip push message
106
+ end
103
107
  end
104
108
 
105
109
  # App 2 (Subscriber)
@@ -115,18 +119,38 @@ class User < ActiveRecord::Base
115
119
  end
116
120
  ```
117
121
 
122
+ Note: Be careful with collision of names
123
+ ```
124
+ class User
125
+ # ps_publish %i[name_data:name name:key] # key will be replaced with name_data
126
+ ps_publish %i[name_data:name key_data:key] # use alias to avoid collision
127
+
128
+ def key_data
129
+ name
130
+ end
131
+ end
132
+ ```
133
+
118
134
  ## API
119
- - To perform a callback before publishing message (CRUD)
135
+ - Permit to cancel sync called after create/update/destroy (Before initializing sync service)
136
+ ```model.ps_skip_callback?(action)```
137
+ Note: Return true to cancel sync
138
+
139
+ - Callback called before preparing data for sync (Permit to stop sync)
140
+ ```model.ps_skip_sync?(action)```
141
+ Note: return true to cancel sync
142
+
143
+ - Callback called before sync (After preparing data)
120
144
  ```model.ps_before_sync(action, data_to_deliver)```
121
- Note: If the method returns ```false```, the message will not be published
145
+ Note: If the method returns ```:cancel```, the sync will be stopped (message will not be published)
122
146
 
123
- - To perform a callback after publishing message (CRUD)
124
- ```model.ps_after_sync(action, data_to_deliver)```
125
- Note: If the method returns ```false```, the message will not be published
147
+ - Callback called after sync
148
+ ```model.ps_after_sync(action, data_delivered)```
126
149
 
127
150
  - Perform sync on demand (:create, :update, :destroy):
128
151
  The target model will receive a notification to perform the indicated action
129
- ```my_model.ps_perform_sync(action_name)```
152
+ ```my_model.ps_perform_sync(action_name, custom_settings = {})```
153
+ * custom_settings: override default settings defined for action_name ({ attrs: [], as_klass: nil, id: nil })
130
154
 
131
155
  - Class level notification:
132
156
  ```User.ps_class_publish(data, action: action_name, as_klass: custom_klass_name)```
@@ -13,10 +13,13 @@ module PubSubModelSync
13
13
  end
14
14
 
15
15
  def process
16
+ @failed = false
16
17
  log 'processing message'
17
18
  listeners = filter_listeners
18
- eval_message(listeners) if listeners.any?
19
- log 'processed message'
19
+ return log 'Skipped: No listeners' unless listeners.any?
20
+
21
+ eval_message(listeners)
22
+ log 'processed message' unless @failed
20
23
  end
21
24
 
22
25
  private
@@ -36,6 +39,7 @@ module PubSubModelSync
36
39
  model_class.send(listener[:action], data)
37
40
  rescue => e
38
41
  log("Error listener (#{listener}): #{e.message}", :error)
42
+ @failed = true
39
43
  end
40
44
 
41
45
  # support for: create, update, destroy
@@ -49,13 +53,13 @@ module PubSubModelSync
49
53
  end
50
54
  rescue => e
51
55
  log("Error listener (#{listener}): #{e.message}", :error)
56
+ @failed = true
52
57
  end
53
58
 
54
59
  def find_model(listener)
55
60
  model_class = listener[:klass].constantize
56
61
  identifier = listener[:settings][:id] || :id
57
- model_class.where(identifier => attrs[:id]).first ||
58
- model_class.new(identifier => attrs[:id])
62
+ model_class.where(identifier => attrs[:id]).first_or_initialize
59
63
  end
60
64
 
61
65
  def populate_model(model, listener)
@@ -30,6 +30,10 @@ module PubSubModelSync
30
30
  def topic(*_args)
31
31
  @topic ||= MockTopic.new
32
32
  end
33
+
34
+ def close
35
+ true
36
+ end
33
37
  end
34
38
 
35
39
  def create_channel(*_args)
@@ -14,12 +14,14 @@ module PubSubModelSync
14
14
 
15
15
  # @param settings (Hash): { attrs: [], as_klass: nil, id: nil }
16
16
  def publish_model(model, action, settings = nil)
17
+ return if model.ps_skip_sync?(action)
18
+
17
19
  settings ||= model.class.ps_publisher_info(action)
18
20
  attributes = build_model_attrs(model, action, settings)
19
21
  data = {}
20
22
  data = build_model_data(model, settings[:attrs]) if action != :destroy
21
23
  res_before = model.ps_before_sync(action, data)
22
- return if res_before == false
24
+ return if res_before == :cancel
23
25
 
24
26
  connector.publish(data.symbolize_keys, attributes)
25
27
  model.ps_after_sync(action, data)
@@ -6,18 +6,28 @@ module PubSubModelSync
6
6
  base.extend(ClassMethods)
7
7
  end
8
8
 
9
- # Permit to skip a publish callback
10
- def ps_skip_for?(_action)
9
+ # Before initializing sync service (callbacks: after create/update/destroy)
10
+ def ps_skip_callback?(_action)
11
11
  false
12
12
  end
13
13
 
14
+ # before preparing data to sync
15
+ def ps_skip_sync?(_action)
16
+ false
17
+ end
18
+
19
+ # before delivering data
14
20
  def ps_before_sync(_action, _data); end
15
21
 
22
+ # after delivering data
16
23
  def ps_after_sync(_action, _data); end
17
24
 
18
- def ps_perform_sync(action = :create)
25
+ # To perform sync on demand
26
+ # @param custom_settings (Hash): { attrs: [], as_klass: nil, id: nil }
27
+ def ps_perform_sync(action = :create, custom_settings = {})
19
28
  service = self.class.ps_publisher_service
20
- service.publish_model(self, action, self.class.ps_publisher_info(action))
29
+ model_settings = self.class.ps_publisher_info(action) || {}
30
+ service.publish_model(self, action, model_settings.merge(custom_settings))
21
31
  end
22
32
 
23
33
  module ClassMethods
@@ -32,12 +42,14 @@ module PubSubModelSync
32
42
  end
33
43
  end
34
44
 
45
+ # Publisher info for specific action
35
46
  def ps_publisher_info(action = :create)
36
47
  PubSubModelSync::Config.publishers.select do |listener|
37
48
  listener[:klass] == name && listener[:action] == action
38
49
  end.last
39
50
  end
40
51
 
52
+ # On demand class level publisher
41
53
  def ps_class_publish(data, action:, as_klass: nil)
42
54
  as_klass = (as_klass || name).to_s
43
55
  ps_publisher_service.publish_data(as_klass, data, action.to_sym)
@@ -51,7 +63,7 @@ module PubSubModelSync
51
63
 
52
64
  def ps_register_callback(action, info)
53
65
  after_commit(on: action) do |model|
54
- unless model.ps_skip_for?(action)
66
+ unless model.ps_skip_callback?(action)
55
67
  service = model.class.ps_publisher_service
56
68
  service.publish_model(model, action.to_sym, info)
57
69
  end
@@ -28,9 +28,12 @@ module PubSubModelSync
28
28
 
29
29
  def publish(data, attributes)
30
30
  log("Publishing: #{[data, attributes]}")
31
- subscribe_to_queue
32
- payload = { data: data, attributes: attributes }
33
- topic.publish(payload.to_json, message_settings)
31
+ deliver_data(data, attributes)
32
+ # TODO: max retry
33
+ rescue Timeout::Error => e
34
+ log("Error publishing (retrying....): #{e.message}", :error)
35
+ initialize
36
+ retry
34
37
  rescue => e
35
38
  info = [data, attributes, e.message, e.backtrace]
36
39
  log("Error publishing: #{info}", :error)
@@ -72,5 +75,16 @@ module PubSubModelSync
72
75
  def log(msg, kind = :info)
73
76
  config.log("Rabbit Service ==> #{msg}", kind)
74
77
  end
78
+
79
+ def deliver_data(data, attributes)
80
+ subscribe_to_queue
81
+ payload = { data: data, attributes: attributes }
82
+ topic.publish(payload.to_json, message_settings)
83
+
84
+ # Ugly fix: "IO timeout when reading 7 bytes"
85
+ # https://stackoverflow.com/questions/39039129/rabbitmq-timeouterror-io-timeout-when-reading-7-bytes
86
+ channel.close
87
+ service.close
88
+ end
75
89
  end
76
90
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PubSubModelSync
4
- VERSION = '0.2.2'
4
+ VERSION = '0.2.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pub_sub_model_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Owen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-28 00:00:00.000000000 Z
11
+ date: 2020-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport