pub_sub_model_sync 0.1.5 → 0.2.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/.github/workflows/ruby.yml +33 -0
- data/CHANGELOG.md +19 -1
- data/Gemfile.lock +63 -47
- data/README.md +63 -11
- data/lib/pub_sub_model_sync/config.rb +3 -3
- 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 +10 -2
- data/lib/pub_sub_model_sync/publisher_concern.rb +30 -9
- data/lib/pub_sub_model_sync/service_rabbit.rb +17 -3
- data/lib/pub_sub_model_sync/version.rb +1 -1
- metadata +4 -5
- data/.travis.yml +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7655730b3b89716b76be52db708b7c93ec64176cc158fc84323d4e811f6dcdf1
|
4
|
+
data.tar.gz: 874aa3f5c5c679fd3e7ec02550426f0824481194ebd99b1a0494180df3a22cc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e8406293a7528fa5d697c2a6a30b4cb00cee900b349ef834fad5fd7771ce864a8338ac95bc1bcbe41568d9efa1737111720607cb0f002e684ab532e835ec651
|
7
|
+
data.tar.gz: 0f995774ddf1b916db02fed9051c26b106e549261877c72a718e9e23c45544dff6c9757231e094201c9d466b2c4922d8e6364f8167697820db5833d78ee85c85
|
@@ -0,0 +1,33 @@
|
|
1
|
+
name: Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
build:
|
12
|
+
name: Tests and Code Style
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- name: Set up Ruby 2.6
|
18
|
+
uses: actions/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: 2.6.x
|
21
|
+
|
22
|
+
- name: Install sqlite3
|
23
|
+
run: sudo apt-get install libsqlite3-dev
|
24
|
+
|
25
|
+
- name: Bundle install
|
26
|
+
run: |
|
27
|
+
gem install bundler
|
28
|
+
bundle install --jobs 4 --retry 3
|
29
|
+
- name: Tests (rspec)
|
30
|
+
run: |
|
31
|
+
bundle exec rspec
|
32
|
+
- name: Code style (Rubocop)
|
33
|
+
run: bundle exec rubocop
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,24 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
# 0.
|
3
|
+
# 0.2.4 (April 28, 2020)
|
4
|
+
- Delegate .publish to the .publisher for better understanding
|
5
|
+
|
6
|
+
# 0.2.3 (April 15, 2020)
|
7
|
+
- Improve helper names
|
8
|
+
- feat: perform manual sync with custom settings
|
9
|
+
- fix for "IO timeout when reading 7 bytes" error (Rabbit)
|
10
|
+
- style: do not print processed message when failed
|
11
|
+
- feat: retry delivery message when failed (RabbitMQ)
|
12
|
+
|
13
|
+
|
14
|
+
# 0.2.2 (March 27, 2020)
|
15
|
+
- fix default value for cattr_accessor in ror < 5.2
|
16
|
+
- add callbacks when publishing a message
|
17
|
+
|
18
|
+
# 0.2.1
|
19
|
+
- Add on demand model sync method
|
20
|
+
|
21
|
+
# 0.2.0
|
4
22
|
- Add apache kafka support
|
5
23
|
- Add Service interface for future references
|
6
24
|
- Improve Services to use a single/common message performer
|
data/Gemfile.lock
CHANGED
@@ -1,58 +1,71 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pub_sub_model_sync (0.
|
4
|
+
pub_sub_model_sync (0.2.4)
|
5
5
|
activesupport
|
6
6
|
rails
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
actioncable (
|
12
|
-
actionpack (=
|
11
|
+
actioncable (6.0.2.2)
|
12
|
+
actionpack (= 6.0.2.2)
|
13
13
|
nio4r (~> 2.0)
|
14
14
|
websocket-driver (>= 0.6.1)
|
15
|
-
|
16
|
-
actionpack (=
|
17
|
-
|
18
|
-
|
15
|
+
actionmailbox (6.0.2.2)
|
16
|
+
actionpack (= 6.0.2.2)
|
17
|
+
activejob (= 6.0.2.2)
|
18
|
+
activerecord (= 6.0.2.2)
|
19
|
+
activestorage (= 6.0.2.2)
|
20
|
+
activesupport (= 6.0.2.2)
|
21
|
+
mail (>= 2.7.1)
|
22
|
+
actionmailer (6.0.2.2)
|
23
|
+
actionpack (= 6.0.2.2)
|
24
|
+
actionview (= 6.0.2.2)
|
25
|
+
activejob (= 6.0.2.2)
|
19
26
|
mail (~> 2.5, >= 2.5.4)
|
20
27
|
rails-dom-testing (~> 2.0)
|
21
|
-
actionpack (
|
22
|
-
actionview (=
|
23
|
-
activesupport (=
|
28
|
+
actionpack (6.0.2.2)
|
29
|
+
actionview (= 6.0.2.2)
|
30
|
+
activesupport (= 6.0.2.2)
|
24
31
|
rack (~> 2.0, >= 2.0.8)
|
25
32
|
rack-test (>= 0.6.3)
|
26
33
|
rails-dom-testing (~> 2.0)
|
27
|
-
rails-html-sanitizer (~> 1.0, >= 1.0
|
28
|
-
|
29
|
-
|
34
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
35
|
+
actiontext (6.0.2.2)
|
36
|
+
actionpack (= 6.0.2.2)
|
37
|
+
activerecord (= 6.0.2.2)
|
38
|
+
activestorage (= 6.0.2.2)
|
39
|
+
activesupport (= 6.0.2.2)
|
40
|
+
nokogiri (>= 1.8.5)
|
41
|
+
actionview (6.0.2.2)
|
42
|
+
activesupport (= 6.0.2.2)
|
30
43
|
builder (~> 3.1)
|
31
44
|
erubi (~> 1.4)
|
32
45
|
rails-dom-testing (~> 2.0)
|
33
|
-
rails-html-sanitizer (~> 1.
|
34
|
-
activejob (
|
35
|
-
activesupport (=
|
46
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
47
|
+
activejob (6.0.2.2)
|
48
|
+
activesupport (= 6.0.2.2)
|
36
49
|
globalid (>= 0.3.6)
|
37
|
-
activemodel (
|
38
|
-
activesupport (=
|
39
|
-
activerecord (
|
40
|
-
activemodel (=
|
41
|
-
activesupport (=
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
activerecord (=
|
50
|
+
activemodel (6.0.2.2)
|
51
|
+
activesupport (= 6.0.2.2)
|
52
|
+
activerecord (6.0.2.2)
|
53
|
+
activemodel (= 6.0.2.2)
|
54
|
+
activesupport (= 6.0.2.2)
|
55
|
+
activestorage (6.0.2.2)
|
56
|
+
actionpack (= 6.0.2.2)
|
57
|
+
activejob (= 6.0.2.2)
|
58
|
+
activerecord (= 6.0.2.2)
|
46
59
|
marcel (~> 0.3.1)
|
47
|
-
activesupport (
|
60
|
+
activesupport (6.0.2.2)
|
48
61
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
49
62
|
i18n (>= 0.7, < 2)
|
50
63
|
minitest (~> 5.1)
|
51
64
|
tzinfo (~> 1.1)
|
65
|
+
zeitwerk (~> 2.2)
|
52
66
|
addressable (2.7.0)
|
53
67
|
public_suffix (>= 2.0.2, < 5.0)
|
54
68
|
amq-protocol (2.3.0)
|
55
|
-
arel (9.0.0)
|
56
69
|
ast (2.4.0)
|
57
70
|
builder (3.2.4)
|
58
71
|
bunny (2.14.3)
|
@@ -106,7 +119,7 @@ GEM
|
|
106
119
|
concurrent-ruby (~> 1.0)
|
107
120
|
jaro_winkler (1.5.4)
|
108
121
|
jwt (2.2.1)
|
109
|
-
loofah (2.
|
122
|
+
loofah (2.5.0)
|
110
123
|
crass (~> 1.0.2)
|
111
124
|
nokogiri (>= 1.5.9)
|
112
125
|
mail (2.7.1)
|
@@ -114,7 +127,7 @@ GEM
|
|
114
127
|
marcel (0.3.3)
|
115
128
|
mimemagic (~> 0.3.2)
|
116
129
|
memoist (0.16.2)
|
117
|
-
method_source (0.
|
130
|
+
method_source (1.0.0)
|
118
131
|
mimemagic (0.3.4)
|
119
132
|
mini_mime (1.0.2)
|
120
133
|
mini_portile2 (2.4.0)
|
@@ -132,30 +145,32 @@ GEM
|
|
132
145
|
rack (2.2.2)
|
133
146
|
rack-test (1.1.0)
|
134
147
|
rack (>= 1.0, < 3)
|
135
|
-
rails (
|
136
|
-
actioncable (=
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
148
|
+
rails (6.0.2.2)
|
149
|
+
actioncable (= 6.0.2.2)
|
150
|
+
actionmailbox (= 6.0.2.2)
|
151
|
+
actionmailer (= 6.0.2.2)
|
152
|
+
actionpack (= 6.0.2.2)
|
153
|
+
actiontext (= 6.0.2.2)
|
154
|
+
actionview (= 6.0.2.2)
|
155
|
+
activejob (= 6.0.2.2)
|
156
|
+
activemodel (= 6.0.2.2)
|
157
|
+
activerecord (= 6.0.2.2)
|
158
|
+
activestorage (= 6.0.2.2)
|
159
|
+
activesupport (= 6.0.2.2)
|
145
160
|
bundler (>= 1.3.0)
|
146
|
-
railties (=
|
161
|
+
railties (= 6.0.2.2)
|
147
162
|
sprockets-rails (>= 2.0.0)
|
148
163
|
rails-dom-testing (2.0.3)
|
149
164
|
activesupport (>= 4.2.0)
|
150
165
|
nokogiri (>= 1.6)
|
151
166
|
rails-html-sanitizer (1.3.0)
|
152
167
|
loofah (~> 2.3)
|
153
|
-
railties (
|
154
|
-
actionpack (=
|
155
|
-
activesupport (=
|
168
|
+
railties (6.0.2.2)
|
169
|
+
actionpack (= 6.0.2.2)
|
170
|
+
activesupport (= 6.0.2.2)
|
156
171
|
method_source
|
157
172
|
rake (>= 0.8.7)
|
158
|
-
thor (>= 0.
|
173
|
+
thor (>= 0.20.3, < 2.0)
|
159
174
|
rainbow (3.0.0)
|
160
175
|
rake (13.0.1)
|
161
176
|
rexml (3.2.4)
|
@@ -189,7 +204,7 @@ GEM
|
|
189
204
|
faraday (~> 0.9)
|
190
205
|
jwt (>= 1.5, < 3.0)
|
191
206
|
multi_json (~> 1.10)
|
192
|
-
sprockets (
|
207
|
+
sprockets (4.0.0)
|
193
208
|
concurrent-ruby (~> 1.0)
|
194
209
|
rack (> 1, < 3)
|
195
210
|
sprockets-rails (3.2.1)
|
@@ -199,12 +214,13 @@ GEM
|
|
199
214
|
sqlite3 (1.4.2)
|
200
215
|
thor (1.0.1)
|
201
216
|
thread_safe (0.3.6)
|
202
|
-
tzinfo (1.2.
|
217
|
+
tzinfo (1.2.7)
|
203
218
|
thread_safe (~> 0.1)
|
204
219
|
unicode-display_width (1.6.1)
|
205
220
|
websocket-driver (0.7.1)
|
206
221
|
websocket-extensions (>= 0.1.0)
|
207
222
|
websocket-extensions (0.1.4)
|
223
|
+
zeitwerk (2.3.0)
|
208
224
|
|
209
225
|
PLATFORMS
|
210
226
|
ruby
|
@@ -221,4 +237,4 @@ DEPENDENCIES
|
|
221
237
|
sqlite3
|
222
238
|
|
223
239
|
BUNDLED WITH
|
224
|
-
2.
|
240
|
+
2.1.4
|
data/README.md
CHANGED
@@ -48,7 +48,7 @@ And then execute: $ bundle install
|
|
48
48
|
- configuration for Apache Kafka (You need kafka installed)
|
49
49
|
```ruby
|
50
50
|
PubSubModelSync::Config.service_name = :kafka
|
51
|
-
PubSubModelSync::Config.kafka_connection = [["kafka1:9092", "
|
51
|
+
PubSubModelSync::Config.kafka_connection = [["kafka1:9092", "localhost:2121"], logger: Rails.logger]
|
52
52
|
PubSubModelSync::Config.topic_name = 'sample-topic'
|
53
53
|
```
|
54
54
|
See details here: https://github.com/zendesk/ruby-kafka
|
@@ -83,6 +83,8 @@ end
|
|
83
83
|
|
84
84
|
# Samples
|
85
85
|
User.create(name: 'test user', email: 'sample@gmail.com') # Review your App 2 to see the created user (only name will be saved)
|
86
|
+
User.new(name: 'test user').ps_perform_sync(:create) # similar to above to perform sync on demand
|
87
|
+
|
86
88
|
User.ps_class_publish({ msg: 'Hello' }, action: :greeting) # User.greeting method (Class method) will be called in App2
|
87
89
|
PubSubModelSync::Publisher.new.publish_data(User, { msg: 'Hello' }, :greeting) # similar to above when not included publisher concern
|
88
90
|
```
|
@@ -95,9 +97,13 @@ class User < ActiveRecord::Base
|
|
95
97
|
include PubSubModelSync::PublisherConcern
|
96
98
|
ps_publish(%i[name:full_name email], actions: %i[update], as_klass: 'Client', id: :client_id)
|
97
99
|
|
98
|
-
def
|
100
|
+
def ps_skip_callback?(_action)
|
99
101
|
false # here logic with action to skip push message
|
100
102
|
end
|
103
|
+
|
104
|
+
def ps_skip_sync?(_action)
|
105
|
+
false # here logic with action to skip push message
|
106
|
+
end
|
101
107
|
end
|
102
108
|
|
103
109
|
# App 2 (Subscriber)
|
@@ -113,6 +119,61 @@ class User < ActiveRecord::Base
|
|
113
119
|
end
|
114
120
|
```
|
115
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
|
+
|
134
|
+
## API
|
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)
|
144
|
+
```model.ps_before_sync(action, data_to_deliver)```
|
145
|
+
Note: If the method returns ```:cancel```, the sync will be stopped (message will not be published)
|
146
|
+
|
147
|
+
- Callback called after sync
|
148
|
+
```model.ps_after_sync(action, data_delivered)```
|
149
|
+
|
150
|
+
- Perform sync on demand (:create, :update, :destroy):
|
151
|
+
The target model will receive a notification to perform the indicated action
|
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 })
|
154
|
+
|
155
|
+
- Class level notification:
|
156
|
+
```User.ps_class_publish(data, action: action_name, as_klass: custom_klass_name)```
|
157
|
+
Target class ```User.action_name``` will be called when message is received
|
158
|
+
* data: (required, :hash) message value to deliver
|
159
|
+
* action_name: (required, :sim) same action name as defined in ps_class_subscribe(...)
|
160
|
+
* as_klass: (optional, :string) same class name as defined in ps_class_subscribe(...)
|
161
|
+
|
162
|
+
- Class level notification (Same as above: on demand call)
|
163
|
+
```PubSubModelSync::Publisher.new.publish_data(Klass_name, data, action_name)```
|
164
|
+
* klass_name: (required, Class) same class name as defined in ps_class_subscribe(...)
|
165
|
+
* data: (required, :hash) message value to deliver
|
166
|
+
* action_name: (required, :sim) same action name as defined in ps_class_subscribe(...)
|
167
|
+
|
168
|
+
- Get crud subscription configured for the class
|
169
|
+
```User.ps_subscriber(action_name)```
|
170
|
+
* action_name (default :create, :sym): can be :create, :update, :destroy
|
171
|
+
- Get crud publisher configured for the class
|
172
|
+
```User.ps_publisher(action_name)```
|
173
|
+
* action_name (default :create, :sym): can be :create, :update, :destroy
|
174
|
+
- Inspect all configured listeners
|
175
|
+
```PubSubModelSync::Config.listeners```
|
176
|
+
|
116
177
|
## Testing with RSpec
|
117
178
|
- Config: (spec/rails_helper.rb)
|
118
179
|
```ruby
|
@@ -178,15 +239,6 @@ end
|
|
178
239
|
expect_any_instance_of(publisher).to receive(:publish_data).with('User', data, action)
|
179
240
|
end
|
180
241
|
```
|
181
|
-
|
182
|
-
There are two special methods to extract crud configuration settings (attrs, id, ...):
|
183
|
-
|
184
|
-
Subscribers: ```User.ps_subscriber```
|
185
|
-
|
186
|
-
Publishers: ```User.ps_publisher```
|
187
|
-
|
188
|
-
Note: Inspect all configured listeners with:
|
189
|
-
``` PubSubModelSync::Config.listeners ```
|
190
242
|
|
191
243
|
## Contributing
|
192
244
|
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
module PubSubModelSync
|
4
4
|
class Config
|
5
|
-
cattr_accessor
|
6
|
-
cattr_accessor
|
7
|
-
cattr_accessor
|
5
|
+
cattr_accessor(:listeners) { [] }
|
6
|
+
cattr_accessor(:publishers) { [] }
|
7
|
+
cattr_accessor(:service_name) { :google }
|
8
8
|
cattr_accessor :logger
|
9
9
|
|
10
10
|
# google service
|
@@ -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)
|
@@ -3,22 +3,30 @@
|
|
3
3
|
module PubSubModelSync
|
4
4
|
class Publisher
|
5
5
|
attr_accessor :connector
|
6
|
+
delegate :publish, to: :connector
|
7
|
+
|
6
8
|
def initialize
|
7
9
|
@connector = PubSubModelSync::Connector.new
|
8
10
|
end
|
9
11
|
|
10
12
|
def publish_data(klass, data, action)
|
11
13
|
attributes = self.class.build_attrs(klass, action)
|
12
|
-
|
14
|
+
publish(data, attributes)
|
13
15
|
end
|
14
16
|
|
15
17
|
# @param settings (Hash): { attrs: [], as_klass: nil, id: nil }
|
16
18
|
def publish_model(model, action, settings = nil)
|
19
|
+
return if model.ps_skip_sync?(action)
|
20
|
+
|
17
21
|
settings ||= model.class.ps_publisher_info(action)
|
18
22
|
attributes = build_model_attrs(model, action, settings)
|
19
23
|
data = {}
|
20
24
|
data = build_model_data(model, settings[:attrs]) if action != :destroy
|
21
|
-
|
25
|
+
res_before = model.ps_before_sync(action, data)
|
26
|
+
return if res_before == :cancel
|
27
|
+
|
28
|
+
publish(data.symbolize_keys, attributes)
|
29
|
+
model.ps_after_sync(action, data)
|
22
30
|
end
|
23
31
|
|
24
32
|
def self.build_attrs(klass, action, id = nil)
|
@@ -6,13 +6,32 @@ 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
|
20
|
+
def ps_before_sync(_action, _data); end
|
21
|
+
|
22
|
+
# after delivering data
|
23
|
+
def ps_after_sync(_action, _data); end
|
24
|
+
|
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 = {})
|
28
|
+
service = self.class.ps_publisher_service
|
29
|
+
model_settings = self.class.ps_publisher_info(action) || {}
|
30
|
+
service.publish_model(self, action, model_settings.merge(custom_settings))
|
31
|
+
end
|
32
|
+
|
14
33
|
module ClassMethods
|
15
|
-
# Permit to publish crud actions (:create, :update, :destroy)
|
34
|
+
# Permit to configure to publish crud actions (:create, :update, :destroy)
|
16
35
|
# @param settings (Hash): { actions: nil, as_klass: nil, id: nil }
|
17
36
|
def ps_publish(attrs, settings = {})
|
18
37
|
actions = settings.delete(:actions) || %i[create update destroy]
|
@@ -23,17 +42,19 @@ module PubSubModelSync
|
|
23
42
|
end
|
24
43
|
end
|
25
44
|
|
45
|
+
# On demand class level publisher
|
46
|
+
def ps_class_publish(data, action:, as_klass: nil)
|
47
|
+
as_klass = (as_klass || name).to_s
|
48
|
+
ps_publisher_service.publish_data(as_klass, data, action.to_sym)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Publisher info for specific action
|
26
52
|
def ps_publisher_info(action = :create)
|
27
53
|
PubSubModelSync::Config.publishers.select do |listener|
|
28
54
|
listener[:klass] == name && listener[:action] == action
|
29
55
|
end.last
|
30
56
|
end
|
31
57
|
|
32
|
-
def ps_class_publish(data, action:, as_klass: nil)
|
33
|
-
as_klass = (as_klass || name).to_s
|
34
|
-
ps_publisher_service.publish_data(as_klass, data, action.to_sym)
|
35
|
-
end
|
36
|
-
|
37
58
|
def ps_publisher_service
|
38
59
|
PubSubModelSync::Publisher.new
|
39
60
|
end
|
@@ -42,7 +63,7 @@ module PubSubModelSync
|
|
42
63
|
|
43
64
|
def ps_register_callback(action, info)
|
44
65
|
after_commit(on: action) do |model|
|
45
|
-
unless model.
|
66
|
+
unless model.ps_skip_callback?(action)
|
46
67
|
service = model.class.ps_publisher_service
|
47
68
|
service.publish_model(model, action.to_sym, info)
|
48
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.
|
4
|
+
version: 0.2.4
|
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-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -101,10 +101,10 @@ executables: []
|
|
101
101
|
extensions: []
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
|
+
- ".github/workflows/ruby.yml"
|
104
105
|
- ".gitignore"
|
105
106
|
- ".rspec"
|
106
107
|
- ".rubocop.yml"
|
107
|
-
- ".travis.yml"
|
108
108
|
- CHANGELOG.md
|
109
109
|
- CODE_OF_CONDUCT.md
|
110
110
|
- Gemfile
|
@@ -155,8 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
155
|
- !ruby/object:Gem::Version
|
156
156
|
version: '0'
|
157
157
|
requirements: []
|
158
|
-
|
159
|
-
rubygems_version: 2.7.7
|
158
|
+
rubygems_version: 3.0.8
|
160
159
|
signing_key:
|
161
160
|
specification_version: 4
|
162
161
|
summary: Permit to sync models between apps through pub/sub
|
data/.travis.yml
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sudo: false
|
3
|
-
language: ruby
|
4
|
-
cache: bundler
|
5
|
-
rvm:
|
6
|
-
- 2.3.1
|
7
|
-
before_install: gem install bundler
|
8
|
-
|
9
|
-
script:
|
10
|
-
- bundle install
|
11
|
-
# disabled cause of: An error occurred while Style/PercentLiteralDelimiters cop
|
12
|
-
# - bundle exec rubocop
|
13
|
-
- bundle exec rspec
|