pub_sub_model_sync 0.5.7.1 → 0.5.9.1
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 +16 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +45 -39
- data/README.md +25 -4
- data/lib/pub_sub_model_sync/message_processor.rb +10 -6
- data/lib/pub_sub_model_sync/message_publisher.rb +21 -6
- data/lib/pub_sub_model_sync/mock_google_service.rb +8 -0
- data/lib/pub_sub_model_sync/payload.rb +6 -6
- data/lib/pub_sub_model_sync/publisher.rb +7 -2
- data/lib/pub_sub_model_sync/service_google.rb +11 -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: 585431eec8ef5f6f9d4b0ccea9069d03ea2849d94f7a8f43464f588da8cfae6c
|
4
|
+
data.tar.gz: 4ebf42b8ca72c0bf150f3c27a9ca9b791532954deb1663c571927324be952589
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f0c786ff6de119c0add336c0182158f4c5ab3b9b74d2f9e3f180b3753ac288ecc8e2c6c88149ad82a627691c924f049eeb5e02c39280ec7ce3d04831b99dd18
|
7
|
+
data.tar.gz: f7ae9286d95af747dd8bd5e21c5f4f87e8aec469077663782103738f7ae9d07fa39b4884f5741e572f17b57a1ce6c358fe8ded7334451aa703559b7367218653
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
# 0.5.9.1 (February 10, 2021)
|
4
|
+
- feat: move :key into headers
|
5
|
+
|
6
|
+
# 0.5.9 (February 10, 2021)
|
7
|
+
- feat: reformat :publish and :process methods to include non silence methods
|
8
|
+
- feat: add notification key to payloads (can be used for caching strategies)
|
9
|
+
|
10
|
+
# 0.5.8.2 (February 05, 2021)
|
11
|
+
- fix: restore google pubsub topic settings
|
12
|
+
|
13
|
+
# 0.5.8.1 (February 05, 2021)
|
14
|
+
- fix: keep message ordering with google pubsub
|
15
|
+
|
16
|
+
# 0.5.8 (January 29, 2021)
|
17
|
+
- fix: keep message ordering with google pubsub
|
18
|
+
|
3
19
|
# 0.5.7.1 (January 26, 2021)
|
4
20
|
- fix: does not call :on_error_processing when processing a message
|
5
21
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pub_sub_model_sync (0.5.
|
4
|
+
pub_sub_model_sync (0.5.9.1)
|
5
5
|
rails
|
6
6
|
|
7
7
|
GEM
|
@@ -78,49 +78,55 @@ GEM
|
|
78
78
|
diff-lcs (1.3)
|
79
79
|
digest-crc (0.5.1)
|
80
80
|
erubi (1.10.0)
|
81
|
-
faraday (
|
81
|
+
faraday (1.1.0)
|
82
82
|
multipart-post (>= 1.2, < 3)
|
83
|
+
ruby2_keywords
|
84
|
+
gapic-common (0.3.4)
|
85
|
+
google-protobuf (~> 3.12, >= 3.12.2)
|
86
|
+
googleapis-common-protos (>= 1.3.9, < 2.0)
|
87
|
+
googleapis-common-protos-types (>= 1.0.4, < 2.0)
|
88
|
+
googleauth (~> 0.9)
|
89
|
+
grpc (~> 1.25)
|
83
90
|
globalid (0.4.2)
|
84
91
|
activesupport (>= 4.2.0)
|
85
|
-
google-cloud-core (1.
|
92
|
+
google-cloud-core (1.5.0)
|
86
93
|
google-cloud-env (~> 1.0)
|
87
|
-
|
88
|
-
|
89
|
-
|
94
|
+
google-cloud-errors (~> 1.0)
|
95
|
+
google-cloud-env (1.4.0)
|
96
|
+
faraday (>= 0.17.3, < 2.0)
|
97
|
+
google-cloud-errors (1.0.1)
|
98
|
+
google-cloud-pubsub (2.3.0)
|
90
99
|
concurrent-ruby (~> 1.1)
|
91
|
-
google-cloud-core (~> 1.
|
92
|
-
google-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
google-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
googleapis-common-protos (1.
|
103
|
-
google-protobuf (~> 3.
|
104
|
-
|
105
|
-
|
106
|
-
googleapis-common-protos-types (1.0.4)
|
107
|
-
google-protobuf (~> 3.0)
|
108
|
-
googleauth (0.9.0)
|
109
|
-
faraday (~> 0.12)
|
100
|
+
google-cloud-core (~> 1.5)
|
101
|
+
google-cloud-pubsub-v1 (~> 0.0)
|
102
|
+
google-cloud-pubsub-v1 (0.1.2)
|
103
|
+
gapic-common (~> 0.3)
|
104
|
+
google-cloud-errors (~> 1.0)
|
105
|
+
grpc-google-iam-v1 (>= 0.6.10, < 2.0)
|
106
|
+
google-protobuf (3.14.0-universal-darwin)
|
107
|
+
googleapis-common-protos (1.3.10)
|
108
|
+
google-protobuf (~> 3.11)
|
109
|
+
googleapis-common-protos-types (>= 1.0.5, < 2.0)
|
110
|
+
grpc (~> 1.27)
|
111
|
+
googleapis-common-protos-types (1.0.5)
|
112
|
+
google-protobuf (~> 3.11)
|
113
|
+
googleauth (0.14.0)
|
114
|
+
faraday (>= 0.17.3, < 2.0)
|
110
115
|
jwt (>= 1.4, < 3.0)
|
111
116
|
memoist (~> 0.16)
|
112
117
|
multi_json (~> 1.11)
|
113
118
|
os (>= 0.9, < 2.0)
|
114
|
-
signet (~> 0.
|
115
|
-
grpc (1.
|
116
|
-
google-protobuf (~> 3.
|
119
|
+
signet (~> 0.14)
|
120
|
+
grpc (1.34.0-universal-darwin)
|
121
|
+
google-protobuf (~> 3.13)
|
117
122
|
googleapis-common-protos-types (~> 1.0)
|
118
|
-
grpc-google-iam-v1 (0.6.
|
119
|
-
|
120
|
-
|
123
|
+
grpc-google-iam-v1 (0.6.10)
|
124
|
+
google-protobuf (~> 3.11)
|
125
|
+
googleapis-common-protos (>= 1.3.10, < 2.0)
|
126
|
+
grpc (~> 1.27)
|
121
127
|
i18n (1.8.2)
|
122
128
|
concurrent-ruby (~> 1.0)
|
123
|
-
jwt (2.2.
|
129
|
+
jwt (2.2.2)
|
124
130
|
loofah (2.8.0)
|
125
131
|
crass (~> 1.0.2)
|
126
132
|
nokogiri (>= 1.5.9)
|
@@ -134,16 +140,16 @@ GEM
|
|
134
140
|
mini_mime (1.0.2)
|
135
141
|
mini_portile2 (2.4.0)
|
136
142
|
minitest (5.14.0)
|
137
|
-
multi_json (1.
|
143
|
+
multi_json (1.15.0)
|
138
144
|
multipart-post (2.1.1)
|
139
145
|
nio4r (2.5.4)
|
140
146
|
nokogiri (1.10.10)
|
141
147
|
mini_portile2 (~> 2.4.0)
|
142
|
-
os (1.
|
148
|
+
os (1.1.1)
|
143
149
|
parallel (1.20.1)
|
144
150
|
parser (2.7.2.0)
|
145
151
|
ast (~> 2.4.1)
|
146
|
-
public_suffix (4.0.
|
152
|
+
public_suffix (4.0.6)
|
147
153
|
rack (2.2.3)
|
148
154
|
rack-test (1.1.0)
|
149
155
|
rack (>= 1.0, < 3)
|
@@ -177,7 +183,6 @@ GEM
|
|
177
183
|
rake (13.0.1)
|
178
184
|
regexp_parser (2.0.1)
|
179
185
|
rexml (3.2.4)
|
180
|
-
rly (0.2.3)
|
181
186
|
rspec (3.9.0)
|
182
187
|
rspec-core (~> 3.9.0)
|
183
188
|
rspec-expectations (~> 3.9.0)
|
@@ -205,9 +210,10 @@ GEM
|
|
205
210
|
ruby-kafka (1.0.0)
|
206
211
|
digest-crc
|
207
212
|
ruby-progressbar (1.10.1)
|
208
|
-
|
213
|
+
ruby2_keywords (0.0.2)
|
214
|
+
signet (0.14.0)
|
209
215
|
addressable (~> 2.3)
|
210
|
-
faraday (
|
216
|
+
faraday (>= 0.17.3, < 2.0)
|
211
217
|
jwt (>= 1.5, < 3.0)
|
212
218
|
multi_json (~> 1.10)
|
213
219
|
sprockets (4.0.2)
|
@@ -235,7 +241,7 @@ DEPENDENCIES
|
|
235
241
|
bundler
|
236
242
|
bunny
|
237
243
|
database_cleaner-active_record
|
238
|
-
google-cloud-pubsub
|
244
|
+
google-cloud-pubsub (> 2.0)
|
239
245
|
pub_sub_model_sync!
|
240
246
|
rake
|
241
247
|
rspec
|
data/README.md
CHANGED
@@ -15,7 +15,7 @@ Add this line to your application's Gemfile:
|
|
15
15
|
```ruby
|
16
16
|
gem 'pub_sub_model_sync'
|
17
17
|
|
18
|
-
gem 'google-cloud-pubsub' # to use google pub/sub service
|
18
|
+
gem 'google-cloud-pubsub', '>= 1.9' # to use google pub/sub service
|
19
19
|
gem 'bunny' # to use rabbit-mq pub/sub service
|
20
20
|
gem 'ruby-kafka' # to use apache kafka pub/sub service
|
21
21
|
```
|
@@ -50,7 +50,19 @@ And then execute: $ bundle install
|
|
50
50
|
PubSubModelSync::Config.kafka_connection = [["kafka1:9092", "localhost:2121"], { logger: Rails.logger }]
|
51
51
|
PubSubModelSync::Config.topic_name = 'sample-topic'
|
52
52
|
```
|
53
|
-
See details here: https://github.com/zendesk/ruby-kafka
|
53
|
+
See details here: https://github.com/zendesk/ruby-kafka
|
54
|
+
|
55
|
+
Kafka Confluence example:
|
56
|
+
```ruby
|
57
|
+
kafka_settings = {
|
58
|
+
sasl_plain_username: '...',
|
59
|
+
sasl_plain_password: '...',
|
60
|
+
ssl_ca_certs_from_system: true,
|
61
|
+
logger: Rails.logger, client_id: 'my-app-name'
|
62
|
+
}
|
63
|
+
PubSubModelSync::Config.kafka_connection = [['...confluent.cloud:9092'], kafka_settings]
|
64
|
+
```
|
65
|
+
Note: You need to create the topic manually on Kafka Confluence
|
54
66
|
|
55
67
|
- Add publishers/subscribers to your models (See examples below)
|
56
68
|
|
@@ -308,10 +320,19 @@ config.debug = true
|
|
308
320
|
|
309
321
|
## TODO
|
310
322
|
- Add alias attributes when subscribing (similar to publisher)
|
311
|
-
- Add flag ```model.
|
323
|
+
- Add flag ```model.ps_process_payload``` to retrieve the payload used to process the pub/sub sync
|
312
324
|
- Auto publish update only if payload has changed
|
313
325
|
- On delete, payload must only be composed by ids
|
314
|
-
-
|
326
|
+
- Feature to publish multiple message at a time with the ability to exclude similar messages by klass and action (use the last one)
|
327
|
+
PubSubModelSync::MessagePublisher.batch_publish({ same_keys: :use_last_as_first|:use_last|:use_first_as_last|:keep*, same_data: :use_last_as_first*|:use_last|:use_first_as_last|:keep })
|
328
|
+
- Add DB table to use as a shield to skip publishing similar notifications or publish partial notifications (similar idea when processing notif)
|
329
|
+
- add callback: on_message_received(payload)
|
330
|
+
- Sometimes the listener service stops listening, debug idea:
|
331
|
+
```subscriber.on_error do
|
332
|
+
log('error gogooogle')
|
333
|
+
end
|
334
|
+
loop{ log(['loooooop:', {l: subscriber.last_error, stopped: subscriber.stopped?, started: subscriber.started?}]); sleep 2 }
|
335
|
+
```
|
315
336
|
|
316
337
|
## Q&A
|
317
338
|
- Error "could not obtain a connection from the pool within 5.000 seconds"
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module PubSubModelSync
|
4
4
|
class MessageProcessor < PubSubModelSync::Base
|
5
|
-
attr_accessor :payload
|
5
|
+
attr_accessor :payload
|
6
6
|
|
7
7
|
# @param payload (Payload): payload to be delivered
|
8
8
|
# @Deprecated: def initialize(data, klass, action)
|
@@ -15,10 +15,16 @@ module PubSubModelSync
|
|
15
15
|
@payload = PubSubModelSync::Payload.new(payload, { klass: klass, action: action })
|
16
16
|
end
|
17
17
|
|
18
|
-
def process
|
18
|
+
def process!
|
19
19
|
filter_subscribers.each(&method(:run_subscriber))
|
20
20
|
end
|
21
21
|
|
22
|
+
def process
|
23
|
+
process!
|
24
|
+
rescue => e
|
25
|
+
notify_error(e)
|
26
|
+
end
|
27
|
+
|
22
28
|
private
|
23
29
|
|
24
30
|
def run_subscriber(subscriber)
|
@@ -29,8 +35,6 @@ module PubSubModelSync
|
|
29
35
|
res = config.on_success_processing.call(payload, { subscriber: subscriber })
|
30
36
|
log "processed message with: #{payload.inspect}" if res != :skip_log
|
31
37
|
end
|
32
|
-
rescue => e
|
33
|
-
raise_error ? raise : print_subscriber_error(e, subscriber)
|
34
38
|
end
|
35
39
|
|
36
40
|
def processable?(subscriber)
|
@@ -40,9 +44,9 @@ module PubSubModelSync
|
|
40
44
|
end
|
41
45
|
|
42
46
|
# @param error (Error)
|
43
|
-
def
|
47
|
+
def notify_error(error)
|
44
48
|
info = [payload, error.message, error.backtrace]
|
45
|
-
res = config.on_error_processing.call(error, { payload: payload
|
49
|
+
res = config.on_error_processing.call(error, { payload: payload })
|
46
50
|
log("Error processing message: #{info}", :error) if res != :skip_log
|
47
51
|
end
|
48
52
|
|
@@ -7,14 +7,20 @@ module PubSubModelSync
|
|
7
7
|
@connector ||= PubSubModelSync::Connector.new
|
8
8
|
end
|
9
9
|
|
10
|
+
# Publishes any value to pubsub
|
11
|
+
# @param klass (String): Class name
|
12
|
+
# @param data (Hash): Data to be delivered
|
13
|
+
# @param action (:symbol): action name
|
10
14
|
def publish_data(klass, data, action)
|
11
|
-
|
15
|
+
attrs = { klass: klass.to_s, action: action.to_sym }
|
16
|
+
payload = PubSubModelSync::Payload.new(data, attrs)
|
12
17
|
publish(payload)
|
13
18
|
end
|
14
19
|
|
15
|
-
#
|
16
|
-
# @param
|
17
|
-
# @param
|
20
|
+
# Publishes model info to pubsub
|
21
|
+
# @param model (ActiveRecord model)
|
22
|
+
# @param action (Sym): Action name
|
23
|
+
# @param publisher (Publisher, optional): Publisher to be used
|
18
24
|
def publish_model(model, action, publisher = nil)
|
19
25
|
return if model.ps_skip_sync?(action)
|
20
26
|
|
@@ -27,7 +33,10 @@ module PubSubModelSync
|
|
27
33
|
model.ps_after_sync(action, payload.data)
|
28
34
|
end
|
29
35
|
|
30
|
-
|
36
|
+
# Publishes payload to pubsub
|
37
|
+
# @attr payload (PubSubModelSync::Payload)
|
38
|
+
# Raises error if exist
|
39
|
+
def publish!(payload)
|
31
40
|
if config.on_before_publish.call(payload) == :cancel
|
32
41
|
log("Publish message cancelled: #{payload}") if config.debug
|
33
42
|
return
|
@@ -36,8 +45,14 @@ module PubSubModelSync
|
|
36
45
|
log("Publishing message: #{[payload]}")
|
37
46
|
connector.publish(payload)
|
38
47
|
config.on_after_publish.call(payload)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Similar to :publish! method
|
51
|
+
# Notifies error via :on_error_publish instead of raising error
|
52
|
+
def publish(payload)
|
53
|
+
publish!(payload)
|
39
54
|
rescue => e
|
40
|
-
|
55
|
+
notify_error(e, payload)
|
41
56
|
end
|
42
57
|
|
43
58
|
private
|
@@ -6,7 +6,8 @@ module PubSubModelSync
|
|
6
6
|
attr_reader :data, :attributes, :headers
|
7
7
|
|
8
8
|
# @param data (Hash: { any value }):
|
9
|
-
# @param attributes (Hash: { klass
|
9
|
+
# @param attributes (Hash: { klass*: string, action*: :sym }):
|
10
|
+
# @param headers (Hash: { key?: string, ...any_key?: anything }):
|
10
11
|
def initialize(data, attributes, headers = {})
|
11
12
|
@data = data
|
12
13
|
@attributes = attributes
|
@@ -31,16 +32,14 @@ module PubSubModelSync
|
|
31
32
|
# Process payload data
|
32
33
|
# (If error will raise exception and wont call on_error_processing callback)
|
33
34
|
def process!
|
34
|
-
|
35
|
-
|
36
|
-
end
|
35
|
+
publisher = PubSubModelSync::MessageProcessor.new(self)
|
36
|
+
publisher.process!
|
37
37
|
end
|
38
38
|
|
39
39
|
# Process payload data
|
40
40
|
# (If error will call on_error_processing callback)
|
41
41
|
def process
|
42
42
|
publisher = PubSubModelSync::MessageProcessor.new(self)
|
43
|
-
yield(publisher) if block_given?
|
44
43
|
publisher.process
|
45
44
|
end
|
46
45
|
|
@@ -48,7 +47,7 @@ module PubSubModelSync
|
|
48
47
|
# (If error will raise exception and wont call on_error_publish callback)
|
49
48
|
def publish!
|
50
49
|
klass = PubSubModelSync::MessagePublisher
|
51
|
-
klass.publish(self
|
50
|
+
klass.publish!(self)
|
52
51
|
end
|
53
52
|
|
54
53
|
# Publish payload to pubsub
|
@@ -70,6 +69,7 @@ module PubSubModelSync
|
|
70
69
|
def build_headers
|
71
70
|
headers[:uuid] ||= SecureRandom.uuid
|
72
71
|
headers[:app_key] ||= PubSubModelSync::Config.subscription_key
|
72
|
+
headers[:key] ||= [klass.to_s, action].join('/')
|
73
73
|
end
|
74
74
|
|
75
75
|
def validate!
|
@@ -11,8 +11,10 @@ module PubSubModelSync
|
|
11
11
|
@as_klass = as_klass || klass
|
12
12
|
end
|
13
13
|
|
14
|
+
# Builds the payload with model information defined for :action (:create|:update|:destroy)
|
14
15
|
def payload(model, action)
|
15
|
-
|
16
|
+
headers = { key: [model.class.name, action, model.id].join('/') }
|
17
|
+
PubSubModelSync::Payload.new(payload_data(model), payload_attrs(model, action), headers)
|
16
18
|
end
|
17
19
|
|
18
20
|
private
|
@@ -29,7 +31,10 @@ module PubSubModelSync
|
|
29
31
|
end
|
30
32
|
|
31
33
|
def payload_attrs(model, action)
|
32
|
-
{
|
34
|
+
{
|
35
|
+
klass: (as_klass || model.class.name).to_s,
|
36
|
+
action: action.to_sym
|
37
|
+
}
|
33
38
|
end
|
34
39
|
end
|
35
40
|
end
|
@@ -7,7 +7,8 @@ end
|
|
7
7
|
|
8
8
|
module PubSubModelSync
|
9
9
|
class ServiceGoogle < ServiceBase
|
10
|
-
LISTEN_SETTINGS = { threads: { callback: 1 } }.freeze
|
10
|
+
LISTEN_SETTINGS = { threads: { callback: 1 }, message_ordering: true }.freeze
|
11
|
+
TOPIC_SETTINGS = {}.freeze
|
11
12
|
SUBSCRIPTION_SETTINGS = { message_ordering: true }.freeze
|
12
13
|
attr_accessor :service, :topic, :subscription, :subscriber
|
13
14
|
|
@@ -15,7 +16,8 @@ module PubSubModelSync
|
|
15
16
|
@service = Google::Cloud::Pubsub.new(project: config.project,
|
16
17
|
credentials: config.credentials)
|
17
18
|
@topic = service.topic(config.topic_name) ||
|
18
|
-
service.create_topic(config.topic_name)
|
19
|
+
service.create_topic(config.topic_name, TOPIC_SETTINGS)
|
20
|
+
topic.enable_message_ordering!
|
19
21
|
end
|
20
22
|
|
21
23
|
def listen_messages
|
@@ -30,7 +32,9 @@ module PubSubModelSync
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def publish(payload)
|
33
|
-
topic.
|
35
|
+
topic.publish_async(payload.to_json, message_headers) do |res|
|
36
|
+
raise 'Failed to publish the message.' unless res.succeeded?
|
37
|
+
end
|
34
38
|
end
|
35
39
|
|
36
40
|
def stop
|
@@ -40,6 +44,10 @@ module PubSubModelSync
|
|
40
44
|
|
41
45
|
private
|
42
46
|
|
47
|
+
def message_headers
|
48
|
+
{ SERVICE_KEY => true, ordering_key: SERVICE_KEY }.merge(PUBLISH_SETTINGS)
|
49
|
+
end
|
50
|
+
|
43
51
|
def subscribe_to_topic
|
44
52
|
topic.subscription(config.subscription_key) ||
|
45
53
|
topic.subscribe(config.subscription_key, SUBSCRIPTION_SETTINGS)
|
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.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Owen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|