pub_sub_model_sync 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|