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 +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +31 -7
- data/lib/pub_sub_model_sync/message_processor.rb +8 -4
- data/lib/pub_sub_model_sync/mock_rabbit_service.rb +4 -0
- data/lib/pub_sub_model_sync/publisher.rb +3 -1
- data/lib/pub_sub_model_sync/publisher_concern.rb +17 -5
- data/lib/pub_sub_model_sync/service_rabbit.rb +17 -3
- data/lib/pub_sub_model_sync/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3016ebc69eba9ccb8b168734db1b947b77a4c9400f48d8228f979a7c1ec9eab8
|
4
|
+
data.tar.gz: 82187606c0411ece3eb0d78db59a8794019e80acd5374ffd92b95b0eee4368f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4335695f26d69f091a2ea1726221aab4b07b712827318adfe16f2d1275cde21a0860ce7562ed266f6a0661eb2b8d634abea0956a4478ad55f70e6c199c8a364
|
7
|
+
data.tar.gz: 9252e45ab27b332d9b50afc93da62a0a039c707a1bb3b219ff4e60c1c4f3dae8eb7a85024fc3d1dab87c006e448e60cf3d1f3d953dad8cc8fced24bd375b47cd
|
data/CHANGELOG.md
CHANGED
@@ -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
|
data/Gemfile.lock
CHANGED
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
|
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
|
-
-
|
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
|
145
|
+
Note: If the method returns ```:cancel```, the sync will be stopped (message will not be published)
|
122
146
|
|
123
|
-
-
|
124
|
-
```model.ps_after_sync(action,
|
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
|
-
|
19
|
-
|
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]).
|
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)
|
@@ -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 ==
|
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
|
-
#
|
10
|
-
def
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
32
|
-
|
33
|
-
|
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
|
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.
|
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-
|
11
|
+
date: 2020-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|