pub_sub_model_sync 0.5.0.1 → 0.5.4
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 +22 -0
- data/Gemfile.lock +1 -1
- data/README.md +34 -19
- data/lib/pub_sub_model_sync/base.rb +7 -0
- data/lib/pub_sub_model_sync/config.rb +6 -5
- data/lib/pub_sub_model_sync/message_processor.rb +17 -7
- data/lib/pub_sub_model_sync/message_publisher.rb +11 -8
- data/lib/pub_sub_model_sync/payload.rb +12 -0
- data/lib/pub_sub_model_sync/publisher.rb +1 -1
- data/lib/pub_sub_model_sync/publisher_concern.rb +2 -3
- data/lib/pub_sub_model_sync/service_base.rb +2 -0
- data/lib/pub_sub_model_sync/service_google.rb +4 -4
- data/lib/pub_sub_model_sync/service_kafka.rb +10 -10
- data/lib/pub_sub_model_sync/service_rabbit.rb +10 -5
- data/lib/pub_sub_model_sync/subscriber.rb +22 -18
- data/lib/pub_sub_model_sync/subscriber_concern.rb +4 -0
- 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: 57e8d23c9e514734a8a45664f641378bbb46e8de5315c536a0f692efcbe29dd2
|
|
4
|
+
data.tar.gz: d0f290dac2b0563ffe5412f85e1a6a6e340e281049755b26dc732a3661501b92
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 351901f98e6c806e7a4efe20abdac65de5bf8f716dc57e1889302eab02d33b3f2f4d449cd0d351fd5ae882d16abe79a77791bea8ad956c52cda47829319eb858
|
|
7
|
+
data.tar.gz: e906d601a8c37b999a8b6d550e605e9c04b67db692cec4b60220ae286bef9adde7132d8614cee4ca7dab9ef43538ae2baede3f07e402c4c21a189b79a9ba6873
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
# 0.5.4 (January 8, 2021)
|
|
4
|
+
- fix: exclude identifiers when syncing model
|
|
5
|
+
- feat: callbacks support for future extra params
|
|
6
|
+
- feat: make connectors configurable
|
|
7
|
+
- feat: add :process! and :process, :publish!, :publish methods to payload
|
|
8
|
+
- feat: auto retry 2 times when "could not obtain a database connection within 5.000 seconds..." error occurs
|
|
9
|
+
|
|
10
|
+
# 0.5.3 (December 30, 2020)
|
|
11
|
+
- fix: kafka consume all messages from different apps
|
|
12
|
+
- style: use the correct consumer key
|
|
13
|
+
|
|
14
|
+
# 0.5.2 (December 30, 2020)
|
|
15
|
+
- fix: rabbitmq deliver messages to all subscribers
|
|
16
|
+
- fix: rabbitmq persist messages to recover after restarting
|
|
17
|
+
|
|
18
|
+
# 0.5.1.1 (December 29, 2020)
|
|
19
|
+
- Hotfix: auto convert class name into string
|
|
20
|
+
|
|
21
|
+
# 0.5.1 (December 24, 2020)
|
|
22
|
+
- feat: rename publisher callbacks to be more understandable
|
|
23
|
+
- feat: add callbacks to listen when processing a message (before saving sync)
|
|
24
|
+
|
|
3
25
|
# 0.5.0.1 (December 22, 2020)
|
|
4
26
|
- fix: add missing rabbit mock method
|
|
5
27
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -28,10 +28,9 @@ And then execute: $ bundle install
|
|
|
28
28
|
```ruby
|
|
29
29
|
# initializers/pub_sub_config.rb
|
|
30
30
|
PubSubModelSync::Config.service_name = :google
|
|
31
|
-
PubSubModelSync::Config.project = 'project-id'
|
|
31
|
+
PubSubModelSync::Config.project = 'google-project-id'
|
|
32
32
|
PubSubModelSync::Config.credentials = 'path-to-the-config'
|
|
33
33
|
PubSubModelSync::Config.topic_name = 'sample-topic'
|
|
34
|
-
PubSubModelSync::Config.subscription_name = 'p1-subscriber'
|
|
35
34
|
```
|
|
36
35
|
See details here:
|
|
37
36
|
https://github.com/googleapis/google-cloud-ruby/tree/master/google-cloud-pubsub
|
|
@@ -40,7 +39,7 @@ And then execute: $ bundle install
|
|
|
40
39
|
```ruby
|
|
41
40
|
PubSubModelSync::Config.service_name = :rabbitmq
|
|
42
41
|
PubSubModelSync::Config.bunny_connection = 'amqp://guest:guest@localhost'
|
|
43
|
-
PubSubModelSync::Config.queue_name = ''
|
|
42
|
+
PubSubModelSync::Config.queue_name = 'model-sync'
|
|
44
43
|
PubSubModelSync::Config.topic_name = 'sample-topic'
|
|
45
44
|
```
|
|
46
45
|
See details here: https://github.com/ruby-amqp/bunny
|
|
@@ -48,7 +47,7 @@ And then execute: $ bundle install
|
|
|
48
47
|
- configuration for Apache Kafka (You need kafka installed)
|
|
49
48
|
```ruby
|
|
50
49
|
PubSubModelSync::Config.service_name = :kafka
|
|
51
|
-
PubSubModelSync::Config.kafka_connection = [["kafka1:9092", "localhost:2121"], logger: Rails.logger]
|
|
50
|
+
PubSubModelSync::Config.kafka_connection = [["kafka1:9092", "localhost:2121"], { logger: Rails.logger }]
|
|
52
51
|
PubSubModelSync::Config.topic_name = 'sample-topic'
|
|
53
52
|
```
|
|
54
53
|
See details here: https://github.com/zendesk/ruby-kafka
|
|
@@ -59,7 +58,13 @@ And then execute: $ bundle install
|
|
|
59
58
|
```ruby
|
|
60
59
|
rake pub_sub_model_sync:start
|
|
61
60
|
```
|
|
62
|
-
Note: Publishers do not need todo this
|
|
61
|
+
Note: Publishers do not need todo this
|
|
62
|
+
Note2 (Rails 6+): Due to Zeitwerk, you need to load listeners manually when syncing outside ```rake pub_sub_model_sync:start```
|
|
63
|
+
```ruby
|
|
64
|
+
# PubSubModelSync::Config.subscribers ==> []
|
|
65
|
+
Rails.application.try(:eager_load!)
|
|
66
|
+
# PubSubModelSync::Config.subscribers ==> [#<PubSubModelSync::Subscriber:0x000.. @klass="Article", @action=:create..., ....]
|
|
67
|
+
```
|
|
63
68
|
|
|
64
69
|
- Check the service status with:
|
|
65
70
|
```PubSubModelSync::MessagePublisher.publish_data('Test message', {sample_value: 10}, :create)```
|
|
@@ -163,6 +168,9 @@ Note: Be careful with collision of names
|
|
|
163
168
|
```.ps_subscriber_changed?(data)```
|
|
164
169
|
By default: ```model.changed?```
|
|
165
170
|
|
|
171
|
+
- Permit to perform custom actions before saving sync of the model (:cancel can be returned to skip sync)
|
|
172
|
+
```.ps_before_save_sync(payload)```
|
|
173
|
+
|
|
166
174
|
### Publishers
|
|
167
175
|
- Permit to configure crud publishers
|
|
168
176
|
```ps_publish(attrs, actions: nil, as_klass: nil)```
|
|
@@ -198,10 +206,13 @@ Note: Be careful with collision of names
|
|
|
198
206
|
* action_name: (required, :sim) Action name
|
|
199
207
|
* as_klass: (optional, :string) Custom class name (Default current model name)
|
|
200
208
|
|
|
201
|
-
-
|
|
209
|
+
- Payload actions
|
|
202
210
|
```ruby
|
|
203
211
|
payload = PubSubModelSync::Payload.new({ title: 'hello' }, { action: :greeting, klass: 'User' })
|
|
204
|
-
payload.publish!
|
|
212
|
+
payload.publish! # publishes notification data. It raises exception if fails and does not call ```:on_error_publishing``` callback
|
|
213
|
+
payload.publish # publishes notification data. On error does not raise exception but calls ```:on_error_publishing``` callback
|
|
214
|
+
payload.process! # process a notification data. It raises exception if fails and does not call ```.on_error_processing``` callback
|
|
215
|
+
payload.publish # process a notification data. It does not raise exception if fails but calls ```.on_error_processing``` callback
|
|
205
216
|
```
|
|
206
217
|
|
|
207
218
|
- Get crud publisher configured for the class
|
|
@@ -274,22 +285,26 @@ config = PubSubModelSync::Config
|
|
|
274
285
|
config.debug = true
|
|
275
286
|
```
|
|
276
287
|
|
|
277
|
-
-
|
|
288
|
+
- ```.subscription_name = 'app-2'```
|
|
289
|
+
Permit to define a custom consumer identifier (Default: Rails application name)
|
|
290
|
+
- ```.debug = true```
|
|
278
291
|
(true/false*) => show advanced log messages
|
|
279
|
-
-
|
|
292
|
+
- ```.logger = Rails.logger```
|
|
280
293
|
(Logger) => define custom logger
|
|
281
|
-
-
|
|
282
|
-
(true/false*) => if true, does not
|
|
283
|
-
-
|
|
294
|
+
- ```.disabled_callback_publisher = ->(_model, _action) { false }```
|
|
295
|
+
(true/false*) => if true, does not listen model callbacks for auto sync (Create/Update/Destroy)
|
|
296
|
+
- ```.on_before_processing = ->(payload, {subscriber:}) { puts payload }```
|
|
297
|
+
(Proc) => called before processing received message (:cancel can be returned to skip processing)
|
|
298
|
+
- ```.on_success_processing = ->(payload, {subscriber:}) { puts payload }```
|
|
284
299
|
(Proc) => called when a message was successfully processed
|
|
285
|
-
-
|
|
286
|
-
(Proc) => called when a message failed when processing
|
|
287
|
-
-
|
|
288
|
-
(Proc) => called before publishing a message
|
|
289
|
-
-
|
|
300
|
+
- ```.on_error_processing = ->(exception, {payload:, subscriber:}) { payload.delay(...).process! }```
|
|
301
|
+
(Proc) => called when a message failed when processing (delayed_job or similar can be used for retrying)
|
|
302
|
+
- ```.on_before_publish = ->(payload) { puts payload }```
|
|
303
|
+
(Proc) => called before publishing a message (:cancel can be returned to skip publishing)
|
|
304
|
+
- ```.on_after_publish = ->(payload) { puts payload }```
|
|
290
305
|
(Proc) => called after publishing a message
|
|
291
|
-
-
|
|
292
|
-
(Proc) => called when failed publishing a message
|
|
306
|
+
- ```.on_error_publish = ->(exception, {payload:}) { payload.delay(...).publish! }```
|
|
307
|
+
(Proc) => called when failed publishing a message (delayed_job or similar can be used for retrying)
|
|
293
308
|
|
|
294
309
|
## TODO
|
|
295
310
|
- Add alias attributes when subscribing (similar to publisher)
|
|
@@ -10,12 +10,13 @@ module PubSubModelSync
|
|
|
10
10
|
cattr_accessor(:debug) { false }
|
|
11
11
|
cattr_accessor :logger # LoggerInst
|
|
12
12
|
|
|
13
|
-
cattr_accessor(:
|
|
14
|
-
cattr_accessor(:
|
|
15
|
-
cattr_accessor(:
|
|
13
|
+
cattr_accessor(:on_before_processing) { ->(_payload, _info) {} } # return :cancel to skip
|
|
14
|
+
cattr_accessor(:on_success_processing) { ->(_payload, _info) {} }
|
|
15
|
+
cattr_accessor(:on_error_processing) { ->(_exception, _info) {} }
|
|
16
|
+
cattr_accessor(:on_before_publish) { ->(_payload) {} } # return :cancel to skip
|
|
16
17
|
cattr_accessor(:on_after_publish) { ->(_payload) {} }
|
|
17
|
-
cattr_accessor(:
|
|
18
|
-
cattr_accessor(:
|
|
18
|
+
cattr_accessor(:on_error_publish) { ->(_exception, _info) {} }
|
|
19
|
+
cattr_accessor(:disabled_callback_publisher) { ->(_model, _action) { false } }
|
|
19
20
|
|
|
20
21
|
# google service
|
|
21
22
|
cattr_accessor :project, :credentials, :topic_name, :subscription_name
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module PubSubModelSync
|
|
4
4
|
class MessageProcessor < PubSubModelSync::Base
|
|
5
|
-
attr_accessor :payload
|
|
5
|
+
attr_accessor :payload, :raise_error
|
|
6
6
|
|
|
7
7
|
# @param payload (Payload): payload to be delivered
|
|
8
8
|
# @Deprecated: def initialize(data, klass, action)
|
|
@@ -22,17 +22,27 @@ module PubSubModelSync
|
|
|
22
22
|
private
|
|
23
23
|
|
|
24
24
|
def run_subscriber(subscriber)
|
|
25
|
-
subscriber
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
return unless processable?(subscriber)
|
|
26
|
+
|
|
27
|
+
retry_error(ActiveRecord::ConnectionTimeoutError, qty: 2) do
|
|
28
|
+
subscriber.process!(payload)
|
|
29
|
+
res = config.on_success_processing.call(payload, { subscriber: subscriber })
|
|
30
|
+
log "processed message with: #{payload.inspect}" if res != :skip_log
|
|
31
|
+
end
|
|
28
32
|
rescue => e
|
|
29
|
-
print_subscriber_error(e)
|
|
33
|
+
raise_error ? raise : print_subscriber_error(e, subscriber)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def processable?(subscriber)
|
|
37
|
+
cancel = config.on_before_processing.call(payload, { subscriber: subscriber }) == :cancel
|
|
38
|
+
log("process message cancelled: #{payload}") if cancel && config.debug
|
|
39
|
+
!cancel
|
|
30
40
|
end
|
|
31
41
|
|
|
32
42
|
# @param error (Error)
|
|
33
|
-
def print_subscriber_error(error)
|
|
43
|
+
def print_subscriber_error(error, subscriber)
|
|
34
44
|
info = [payload, error.message, error.backtrace]
|
|
35
|
-
res = config.
|
|
45
|
+
res = config.on_error_processing.call(error, { payload: payload, subscriber: subscriber })
|
|
36
46
|
log("Error processing message: #{info}", :error) if res != :skip_log
|
|
37
47
|
end
|
|
38
48
|
|
|
@@ -8,7 +8,7 @@ module PubSubModelSync
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def publish_data(klass, data, action)
|
|
11
|
-
payload = PubSubModelSync::Payload.new(data, { klass: klass, action: action.to_sym })
|
|
11
|
+
payload = PubSubModelSync::Payload.new(data, { klass: klass.to_s, action: action.to_sym })
|
|
12
12
|
publish(payload)
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -19,8 +19,7 @@ module PubSubModelSync
|
|
|
19
19
|
return if model.ps_skip_sync?(action)
|
|
20
20
|
|
|
21
21
|
publisher ||= model.class.ps_publisher(action)
|
|
22
|
-
|
|
23
|
-
payload = PubSubModelSync::Payload.new(payload_info[:data], payload_info[:attrs])
|
|
22
|
+
payload = publisher.payload(model, action)
|
|
24
23
|
res_before = model.ps_before_sync(action, payload.data)
|
|
25
24
|
return if res_before == :cancel
|
|
26
25
|
|
|
@@ -28,20 +27,24 @@ module PubSubModelSync
|
|
|
28
27
|
model.ps_after_sync(action, payload.data)
|
|
29
28
|
end
|
|
30
29
|
|
|
31
|
-
def publish(payload)
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
def publish(payload, raise_error: false)
|
|
31
|
+
if config.on_before_publish.call(payload) == :cancel
|
|
32
|
+
log("Publish message cancelled: #{payload}") if config.debug
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
log("Publishing message: #{[payload]}")
|
|
34
37
|
connector.publish(payload)
|
|
35
38
|
config.on_after_publish.call(payload)
|
|
36
39
|
rescue => e
|
|
37
|
-
notify_error(e, payload)
|
|
40
|
+
raise_error ? raise : notify_error(e, payload)
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
private
|
|
41
44
|
|
|
42
45
|
def notify_error(exception, payload)
|
|
43
46
|
info = [payload, exception.message, exception.backtrace]
|
|
44
|
-
res = config.
|
|
47
|
+
res = config.on_error_publish.call(exception, { payload: payload })
|
|
45
48
|
log("Error publishing: #{info}", :error) if res != :skip_log
|
|
46
49
|
end
|
|
47
50
|
end
|
|
@@ -26,11 +26,23 @@ module PubSubModelSync
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def process!
|
|
29
|
+
process do |publisher|
|
|
30
|
+
publisher.raise_error = true
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def process
|
|
29
35
|
publisher = PubSubModelSync::MessageProcessor.new(self)
|
|
36
|
+
yield(publisher) if block_given?
|
|
30
37
|
publisher.process
|
|
31
38
|
end
|
|
32
39
|
|
|
33
40
|
def publish!
|
|
41
|
+
klass = PubSubModelSync::MessagePublisher
|
|
42
|
+
klass.publish(self, raise_error: true)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def publish
|
|
34
46
|
klass = PubSubModelSync::MessagePublisher
|
|
35
47
|
klass.publish(self)
|
|
36
48
|
end
|
|
@@ -11,13 +11,12 @@ module PubSubModelSync
|
|
|
11
11
|
false
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
# TODO: make it using respond_to?(:ps_skip_sync?)
|
|
15
14
|
# before preparing data to sync
|
|
16
15
|
def ps_skip_sync?(_action)
|
|
17
16
|
false
|
|
18
17
|
end
|
|
19
18
|
|
|
20
|
-
# before delivering data
|
|
19
|
+
# before delivering data (return :cancel to cancel sync)
|
|
21
20
|
def ps_before_sync(_action, _data); end
|
|
22
21
|
|
|
23
22
|
# after delivering data
|
|
@@ -64,7 +63,7 @@ module PubSubModelSync
|
|
|
64
63
|
|
|
65
64
|
def ps_register_callback(action, publisher)
|
|
66
65
|
after_commit(on: action) do |model|
|
|
67
|
-
disabled = PubSubModelSync::Config.
|
|
66
|
+
disabled = PubSubModelSync::Config.disabled_callback_publisher.call(model, action)
|
|
68
67
|
if !disabled && !model.ps_skip_callback?(action)
|
|
69
68
|
klass = PubSubModelSync::MessagePublisher
|
|
70
69
|
klass.publish_model(model, action.to_sym, publisher)
|
|
@@ -4,6 +4,8 @@ require 'pub_sub_model_sync/payload'
|
|
|
4
4
|
module PubSubModelSync
|
|
5
5
|
class ServiceBase < PubSubModelSync::Base
|
|
6
6
|
SERVICE_KEY = 'service_model_sync'
|
|
7
|
+
PUBLISH_SETTINGS = {}.freeze
|
|
8
|
+
LISTEN_SETTINGS = {}.freeze
|
|
7
9
|
|
|
8
10
|
def listen_messages
|
|
9
11
|
raise 'method :listen_messages must be defined in service'
|
|
@@ -18,7 +18,7 @@ module PubSubModelSync
|
|
|
18
18
|
|
|
19
19
|
def listen_messages
|
|
20
20
|
@subscription = subscribe_to_topic
|
|
21
|
-
@subscriber = subscription.listen(&method(:process_message))
|
|
21
|
+
@subscriber = subscription.listen(LISTEN_SETTINGS, &method(:process_message))
|
|
22
22
|
log('Listener starting...')
|
|
23
23
|
subscriber.start
|
|
24
24
|
log('Listener started')
|
|
@@ -28,7 +28,7 @@ module PubSubModelSync
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def publish(payload)
|
|
31
|
-
topic.publish(payload.to_json, { SERVICE_KEY => true })
|
|
31
|
+
topic.publish(payload.to_json, { SERVICE_KEY => true }.merge(PUBLISH_SETTINGS))
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def stop
|
|
@@ -39,8 +39,8 @@ module PubSubModelSync
|
|
|
39
39
|
private
|
|
40
40
|
|
|
41
41
|
def subscribe_to_topic
|
|
42
|
-
topic.subscription(config.
|
|
43
|
-
topic.subscribe(config.
|
|
42
|
+
topic.subscription(config.subscription_key) ||
|
|
43
|
+
topic.subscribe(config.subscription_key)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def process_message(received_message)
|
|
@@ -10,17 +10,17 @@ module PubSubModelSync
|
|
|
10
10
|
cattr_accessor :producer
|
|
11
11
|
attr_accessor :config, :service, :consumer
|
|
12
12
|
|
|
13
|
-
CONSUMER_GROUP = 'service_model_sync'
|
|
14
|
-
|
|
15
13
|
def initialize
|
|
16
14
|
@config = PubSubModelSync::Config
|
|
17
|
-
|
|
15
|
+
settings = config.kafka_connection
|
|
16
|
+
settings[1][:client_id] ||= config.subscription_key
|
|
17
|
+
@service = Kafka.new(*settings)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def listen_messages
|
|
21
21
|
log('Listener starting...')
|
|
22
22
|
start_consumer
|
|
23
|
-
consumer.each_message(&method(:process_message))
|
|
23
|
+
consumer.each_message(LISTEN_SETTINGS, &method(:process_message))
|
|
24
24
|
rescue PubSubModelSync::Runner::ShutDown
|
|
25
25
|
log('Listener stopped')
|
|
26
26
|
rescue => e
|
|
@@ -28,7 +28,11 @@ module PubSubModelSync
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def publish(payload)
|
|
31
|
-
|
|
31
|
+
settings = {
|
|
32
|
+
topic: config.topic_name,
|
|
33
|
+
headers: { SERVICE_KEY => true }
|
|
34
|
+
}.merge(PUBLISH_SETTINGS)
|
|
35
|
+
producer.produce(payload.to_json, settings)
|
|
32
36
|
producer.deliver_messages
|
|
33
37
|
end
|
|
34
38
|
|
|
@@ -39,12 +43,8 @@ module PubSubModelSync
|
|
|
39
43
|
|
|
40
44
|
private
|
|
41
45
|
|
|
42
|
-
def message_settings
|
|
43
|
-
{ topic: config.topic_name, headers: { SERVICE_KEY => true } }
|
|
44
|
-
end
|
|
45
|
-
|
|
46
46
|
def start_consumer
|
|
47
|
-
@consumer = service.consumer(group_id:
|
|
47
|
+
@consumer = service.consumer(group_id: config.subscription_key)
|
|
48
48
|
consumer.subscribe(config.topic_name)
|
|
49
49
|
end
|
|
50
50
|
|
|
@@ -40,6 +40,7 @@ module PubSubModelSync
|
|
|
40
40
|
|
|
41
41
|
def stop
|
|
42
42
|
log('Listener stopping...')
|
|
43
|
+
channel&.close
|
|
43
44
|
service.close
|
|
44
45
|
end
|
|
45
46
|
|
|
@@ -48,12 +49,17 @@ module PubSubModelSync
|
|
|
48
49
|
def message_settings
|
|
49
50
|
{
|
|
50
51
|
routing_key: queue.name,
|
|
51
|
-
type: SERVICE_KEY
|
|
52
|
-
|
|
52
|
+
type: SERVICE_KEY,
|
|
53
|
+
persistent: true
|
|
54
|
+
}.merge(PUBLISH_SETTINGS)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def queue_settings
|
|
58
|
+
{ durable: true, auto_delete: false }
|
|
53
59
|
end
|
|
54
60
|
|
|
55
61
|
def subscribe_settings
|
|
56
|
-
{ manual_ack: false }
|
|
62
|
+
{ manual_ack: false }.merge(LISTEN_SETTINGS)
|
|
57
63
|
end
|
|
58
64
|
|
|
59
65
|
def process_message(_delivery_info, meta_info, payload)
|
|
@@ -65,8 +71,7 @@ module PubSubModelSync
|
|
|
65
71
|
def subscribe_to_queue
|
|
66
72
|
service.start
|
|
67
73
|
@channel = service.create_channel
|
|
68
|
-
|
|
69
|
-
@queue = channel.queue(config.queue_name, queue_settings)
|
|
74
|
+
@queue = channel.queue(config.subscription_key, queue_settings)
|
|
70
75
|
subscribe_to_exchange
|
|
71
76
|
end
|
|
72
77
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module PubSubModelSync
|
|
4
4
|
class Subscriber
|
|
5
|
-
attr_accessor :klass, :action, :attrs, :settings
|
|
5
|
+
attr_accessor :klass, :action, :attrs, :settings, :identifiers
|
|
6
|
+
attr_reader :payload
|
|
6
7
|
|
|
7
8
|
# @param settings: (Hash) { id: :id, direct_mode: false,
|
|
8
9
|
# from_klass: klass, from_action: action }
|
|
@@ -13,50 +14,53 @@ module PubSubModelSync
|
|
|
13
14
|
@action = action
|
|
14
15
|
@attrs = attrs
|
|
15
16
|
@settings = def_settings.merge(settings)
|
|
17
|
+
@identifiers = Array(settings[:id]).map(&:to_sym)
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
def
|
|
20
|
+
def process!(payload)
|
|
21
|
+
@payload = payload
|
|
19
22
|
if settings[:direct_mode]
|
|
20
|
-
run_class_message
|
|
23
|
+
run_class_message
|
|
21
24
|
else
|
|
22
|
-
run_model_message
|
|
25
|
+
run_model_message
|
|
23
26
|
end
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
private
|
|
27
30
|
|
|
28
|
-
def run_class_message
|
|
31
|
+
def run_class_message
|
|
29
32
|
model_class = klass.constantize
|
|
30
|
-
model_class.send(action,
|
|
33
|
+
model_class.send(action, payload.data)
|
|
31
34
|
end
|
|
32
35
|
|
|
33
36
|
# support for: create, update, destroy
|
|
34
|
-
def run_model_message
|
|
35
|
-
model = find_model
|
|
37
|
+
def run_model_message
|
|
38
|
+
model = find_model
|
|
39
|
+
return if model.ps_before_save_sync(payload) == :cancel
|
|
40
|
+
|
|
36
41
|
if action == :destroy
|
|
37
42
|
model.destroy!
|
|
38
43
|
else
|
|
39
|
-
populate_model(model
|
|
40
|
-
return if action == :update && !model.ps_subscriber_changed?(
|
|
44
|
+
populate_model(model)
|
|
45
|
+
return if action == :update && !model.ps_subscriber_changed?(payload.data)
|
|
41
46
|
|
|
42
47
|
model.save!
|
|
43
48
|
end
|
|
44
49
|
end
|
|
45
50
|
|
|
46
|
-
def find_model
|
|
51
|
+
def find_model
|
|
47
52
|
model_class = klass.constantize
|
|
48
|
-
return model_class.ps_find_model(
|
|
53
|
+
return model_class.ps_find_model(payload.data) if model_class.respond_to?(:ps_find_model)
|
|
49
54
|
|
|
50
|
-
model_class.where(model_identifiers
|
|
55
|
+
model_class.where(model_identifiers).first_or_initialize
|
|
51
56
|
end
|
|
52
57
|
|
|
53
|
-
def model_identifiers
|
|
54
|
-
identifiers
|
|
55
|
-
identifiers.map { |key| [key, message[key.to_sym]] }.to_h
|
|
58
|
+
def model_identifiers
|
|
59
|
+
identifiers.map { |key| [key, payload.data[key.to_sym]] }.to_h
|
|
56
60
|
end
|
|
57
61
|
|
|
58
|
-
def populate_model(model
|
|
59
|
-
values =
|
|
62
|
+
def populate_model(model)
|
|
63
|
+
values = payload.data.slice(*attrs).except(*identifiers)
|
|
60
64
|
values.each do |attr, value|
|
|
61
65
|
model.send("#{attr}=", value)
|
|
62
66
|
end
|
|
@@ -12,6 +12,10 @@ module PubSubModelSync
|
|
|
12
12
|
changed?
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
# permit to apply custom actions before applying sync
|
|
16
|
+
# @return (nil|:cancel): nil to continue sync OR :cancel to skip sync
|
|
17
|
+
def ps_before_save_sync(_payload); end
|
|
18
|
+
|
|
15
19
|
module ClassMethods
|
|
16
20
|
def ps_subscribe(attrs, actions: nil, from_klass: name, id: :id)
|
|
17
21
|
settings = { id: id, from_klass: from_klass }
|
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.5.
|
|
4
|
+
version: 0.5.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Owen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-01-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|