pub_sub_model_sync 0.2.0 → 0.3.0
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/.idea/.gitignore +8 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/codeStyles/codeStyleConfig.xml +5 -0
- data/.idea/encodings.xml +4 -0
- data/.idea/inspectionProfiles/Project_Default.xml +16 -0
- data/.idea/misc.xml +7 -0
- data/.idea/modules.xml +8 -0
- data/.idea/pub_sub_model_sync.iml +96 -0
- data/.idea/vcs.xml +6 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +68 -47
- data/README.md +101 -18
- data/lib/pub_sub_model_sync/config.rb +3 -3
- data/lib/pub_sub_model_sync/connector.rb +0 -1
- data/lib/pub_sub_model_sync/message_processor.rb +27 -15
- data/lib/pub_sub_model_sync/mock_rabbit_service.rb +4 -0
- data/lib/pub_sub_model_sync/publisher.rb +17 -15
- data/lib/pub_sub_model_sync/publisher_concern.rb +35 -14
- data/lib/pub_sub_model_sync/service_base.rb +2 -2
- data/lib/pub_sub_model_sync/service_rabbit.rb +17 -3
- data/lib/pub_sub_model_sync/subscriber_concern.rb +7 -8
- data/lib/pub_sub_model_sync/version.rb +1 -1
- metadata +13 -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: 04acaa2b5befa05fd52978367afdb24c6a1a5858e10441620a2860a57ea9cd55
|
4
|
+
data.tar.gz: 25297748dd5e1099f9f251d73f7f94c0680e9c04820c3396143f9b3ca17170ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dea58e39fd6d77599000a932f7db942052d5309069c8adb0e571fcb2b7be4a5d4429048371b5bac51c18ff9f016dc88fc0e85ea73ca04bc93f36536c580ea544
|
7
|
+
data.tar.gz: cead04daf416641b5d900d4c8c6a13509c49fa8256dd343552c70b578f5af3a3ba39465069999688418e4de60ba4f9a62b4e40e3b54c0c55dd89dcf366f28ab2
|
@@ -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/.idea/.gitignore
ADDED
data/.idea/.rakeTasks
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Settings><!--This file was automatically generated by Ruby plugin.
|
3
|
+
You are allowed to:
|
4
|
+
1. Remove rake task
|
5
|
+
2. Add existing rake tasks
|
6
|
+
To add existing rake tasks automatically delete this file and reload the project.
|
7
|
+
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build pub_sub_model_sync-0.1.0.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Remove any temporary products" fullCmd="clean" taksId="clean" /><RakeTask description="Remove any generated files" fullCmd="clobber" taksId="clobber" /><RakeTask description="Build and install pub_sub_model_sync-0.1.0.gem into system gems" fullCmd="install" taksId="install" /><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Build and install pub_sub_model_sync-0.1.0.gem into system gems without network access" fullCmd="install:local" taksId="local" /></RakeGroup><RakeTask description="Create tag v0.1.0 and build and push pub_sub_model_sync-0.1.0.gem to TODO: Set to 'http://mygemserver.com'" fullCmd="release[remote]" taksId="release[remote]" /><RakeTask description="Run RSpec code examples" fullCmd="spec" taksId="spec" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
|
data/.idea/encodings.xml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
<component name="InspectionProjectProfileManager">
|
2
|
+
<profile version="1.0">
|
3
|
+
<option name="myName" value="Project Default" />
|
4
|
+
<inspection_tool class="Rubocop" enabled="true" level="WARNING" enabled_by_default="true">
|
5
|
+
<option name="mySeverityMap">
|
6
|
+
<map>
|
7
|
+
<entry key="convention" value="ERROR" />
|
8
|
+
<entry key="error" value="ERROR" />
|
9
|
+
<entry key="fatal" value="ERROR" />
|
10
|
+
<entry key="refactor" value="ERROR" />
|
11
|
+
<entry key="warning" value="ERROR" />
|
12
|
+
</map>
|
13
|
+
</option>
|
14
|
+
</inspection_tool>
|
15
|
+
</profile>
|
16
|
+
</component>
|
data/.idea/misc.xml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="JavaScriptSettings">
|
4
|
+
<option name="languageLevel" value="ES6" />
|
5
|
+
</component>
|
6
|
+
<component name="ProjectRootManager" version="2" project-jdk-name="RVM: ruby-2.5.3" project-jdk-type="RUBY_SDK" />
|
7
|
+
</project>
|
data/.idea/modules.xml
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="ProjectModuleManager">
|
4
|
+
<modules>
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/pub_sub_model_sync.iml" filepath="$PROJECT_DIR$/.idea/pub_sub_model_sync.iml" />
|
6
|
+
</modules>
|
7
|
+
</component>
|
8
|
+
</project>
|
@@ -0,0 +1,96 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<module type="RUBY_MODULE" version="4">
|
3
|
+
<component name="ModuleRunConfigurationManager">
|
4
|
+
<shared />
|
5
|
+
</component>
|
6
|
+
<component name="NewModuleRootManager">
|
7
|
+
<content url="file://$MODULE_DIR$" />
|
8
|
+
<orderEntry type="jdk" jdkName="RVM: ruby-2.6.5" jdkType="RUBY_SDK" />
|
9
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
10
|
+
<orderEntry type="library" scope="PROVIDED" name="actioncable (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
11
|
+
<orderEntry type="library" scope="PROVIDED" name="actionmailbox (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
12
|
+
<orderEntry type="library" scope="PROVIDED" name="actionmailer (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
13
|
+
<orderEntry type="library" scope="PROVIDED" name="actionpack (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
14
|
+
<orderEntry type="library" scope="PROVIDED" name="actiontext (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
15
|
+
<orderEntry type="library" scope="PROVIDED" name="actionview (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
16
|
+
<orderEntry type="library" scope="PROVIDED" name="activejob (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
17
|
+
<orderEntry type="library" scope="PROVIDED" name="activemodel (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
18
|
+
<orderEntry type="library" scope="PROVIDED" name="activerecord (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
19
|
+
<orderEntry type="library" scope="PROVIDED" name="activestorage (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
20
|
+
<orderEntry type="library" scope="PROVIDED" name="activesupport (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
21
|
+
<orderEntry type="library" scope="PROVIDED" name="addressable (v2.7.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
22
|
+
<orderEntry type="library" scope="PROVIDED" name="amq-protocol (v2.3.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
23
|
+
<orderEntry type="library" scope="PROVIDED" name="ast (v2.4.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
24
|
+
<orderEntry type="library" scope="PROVIDED" name="builder (v3.2.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
25
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.1.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
26
|
+
<orderEntry type="library" scope="PROVIDED" name="bunny (v2.14.3, RVM: ruby-2.6.5) [gem]" level="application" />
|
27
|
+
<orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.1.6, RVM: ruby-2.6.5) [gem]" level="application" />
|
28
|
+
<orderEntry type="library" scope="PROVIDED" name="crass (v1.0.6, RVM: ruby-2.6.5) [gem]" level="application" />
|
29
|
+
<orderEntry type="library" scope="PROVIDED" name="database_cleaner (v1.8.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
30
|
+
<orderEntry type="library" scope="PROVIDED" name="database_cleaner-active_record (v1.8.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
31
|
+
<orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.3, RVM: ruby-2.6.5) [gem]" level="application" />
|
32
|
+
<orderEntry type="library" scope="PROVIDED" name="digest-crc (v0.5.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
33
|
+
<orderEntry type="library" scope="PROVIDED" name="erubi (v1.9.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
34
|
+
<orderEntry type="library" scope="PROVIDED" name="faraday (v0.17.3, RVM: ruby-2.6.5) [gem]" level="application" />
|
35
|
+
<orderEntry type="library" scope="PROVIDED" name="globalid (v0.4.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
36
|
+
<orderEntry type="library" scope="PROVIDED" name="google-cloud-core (v1.3.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
37
|
+
<orderEntry type="library" scope="PROVIDED" name="google-cloud-env (v1.2.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
38
|
+
<orderEntry type="library" scope="PROVIDED" name="google-cloud-pubsub (v1.0.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
39
|
+
<orderEntry type="library" scope="PROVIDED" name="google-gax (v1.7.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
40
|
+
<orderEntry type="library" scope="PROVIDED" name="google-protobuf (v3.11.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
41
|
+
<orderEntry type="library" scope="PROVIDED" name="googleapis-common-protos (v1.3.9, RVM: ruby-2.6.5) [gem]" level="application" />
|
42
|
+
<orderEntry type="library" scope="PROVIDED" name="googleapis-common-protos-types (v1.0.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
43
|
+
<orderEntry type="library" scope="PROVIDED" name="googleauth (v0.9.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
44
|
+
<orderEntry type="library" scope="PROVIDED" name="grpc (v1.27.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
45
|
+
<orderEntry type="library" scope="PROVIDED" name="grpc-google-iam-v1 (v0.6.9, RVM: ruby-2.6.5) [gem]" level="application" />
|
46
|
+
<orderEntry type="library" scope="PROVIDED" name="i18n (v1.8.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
47
|
+
<orderEntry type="library" scope="PROVIDED" name="jaro_winkler (v1.5.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
48
|
+
<orderEntry type="library" scope="PROVIDED" name="jwt (v2.2.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
49
|
+
<orderEntry type="library" scope="PROVIDED" name="loofah (v2.5.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
50
|
+
<orderEntry type="library" scope="PROVIDED" name="mail (v2.7.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
51
|
+
<orderEntry type="library" scope="PROVIDED" name="marcel (v0.3.3, RVM: ruby-2.6.5) [gem]" level="application" />
|
52
|
+
<orderEntry type="library" scope="PROVIDED" name="memoist (v0.16.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
53
|
+
<orderEntry type="library" scope="PROVIDED" name="method_source (v1.0.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
54
|
+
<orderEntry type="library" scope="PROVIDED" name="mimemagic (v0.3.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
55
|
+
<orderEntry type="library" scope="PROVIDED" name="mini_mime (v1.0.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
56
|
+
<orderEntry type="library" scope="PROVIDED" name="mini_portile2 (v2.4.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
57
|
+
<orderEntry type="library" scope="PROVIDED" name="minitest (v5.14.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
58
|
+
<orderEntry type="library" scope="PROVIDED" name="multi_json (v1.14.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
59
|
+
<orderEntry type="library" scope="PROVIDED" name="multipart-post (v2.1.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
60
|
+
<orderEntry type="library" scope="PROVIDED" name="nio4r (v2.5.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
61
|
+
<orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.10.9, RVM: ruby-2.6.5) [gem]" level="application" />
|
62
|
+
<orderEntry type="library" scope="PROVIDED" name="os (v1.0.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
63
|
+
<orderEntry type="library" scope="PROVIDED" name="parallel (v1.19.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
64
|
+
<orderEntry type="library" scope="PROVIDED" name="parser (v2.7.0.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
65
|
+
<orderEntry type="library" scope="PROVIDED" name="public_suffix (v4.0.3, RVM: ruby-2.6.5) [gem]" level="application" />
|
66
|
+
<orderEntry type="library" scope="PROVIDED" name="rack (v2.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
67
|
+
<orderEntry type="library" scope="PROVIDED" name="rack-test (v1.1.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
68
|
+
<orderEntry type="library" scope="PROVIDED" name="rails (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
69
|
+
<orderEntry type="library" scope="PROVIDED" name="rails-dom-testing (v2.0.3, RVM: ruby-2.6.5) [gem]" level="application" />
|
70
|
+
<orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.3.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
71
|
+
<orderEntry type="library" scope="PROVIDED" name="railties (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
72
|
+
<orderEntry type="library" scope="PROVIDED" name="rainbow (v3.0.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
73
|
+
<orderEntry type="library" scope="PROVIDED" name="rake (v13.0.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
74
|
+
<orderEntry type="library" scope="PROVIDED" name="rexml (v3.2.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
75
|
+
<orderEntry type="library" scope="PROVIDED" name="rly (v0.2.3, RVM: ruby-2.6.5) [gem]" level="application" />
|
76
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec (v3.9.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
77
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-core (v3.9.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
78
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.9.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
79
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.9.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
80
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.9.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
81
|
+
<orderEntry type="library" scope="PROVIDED" name="rubocop (v0.80.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
82
|
+
<orderEntry type="library" scope="PROVIDED" name="ruby-kafka (v1.0.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
83
|
+
<orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.10.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
84
|
+
<orderEntry type="library" scope="PROVIDED" name="signet (v0.11.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
85
|
+
<orderEntry type="library" scope="PROVIDED" name="sprockets (v4.0.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
86
|
+
<orderEntry type="library" scope="PROVIDED" name="sprockets-rails (v3.2.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
87
|
+
<orderEntry type="library" scope="PROVIDED" name="sqlite3 (v1.4.2, RVM: ruby-2.6.5) [gem]" level="application" />
|
88
|
+
<orderEntry type="library" scope="PROVIDED" name="thor (v1.0.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
89
|
+
<orderEntry type="library" scope="PROVIDED" name="thread_safe (v0.3.6, RVM: ruby-2.6.5) [gem]" level="application" />
|
90
|
+
<orderEntry type="library" scope="PROVIDED" name="tzinfo (v1.2.7, RVM: ruby-2.6.5) [gem]" level="application" />
|
91
|
+
<orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v1.6.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
92
|
+
<orderEntry type="library" scope="PROVIDED" name="websocket-driver (v0.7.1, RVM: ruby-2.6.5) [gem]" level="application" />
|
93
|
+
<orderEntry type="library" scope="PROVIDED" name="websocket-extensions (v0.1.4, RVM: ruby-2.6.5) [gem]" level="application" />
|
94
|
+
<orderEntry type="library" scope="PROVIDED" name="zeitwerk (v2.3.0, RVM: ruby-2.6.5) [gem]" level="application" />
|
95
|
+
</component>
|
96
|
+
</module>
|
data/.idea/vcs.xml
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
# 0.3.0 (April 29, 2020)
|
4
|
+
- Support for multiple identifiers when syncing
|
5
|
+
- Add klass.ps_find_model method for a custom model finder
|
6
|
+
|
7
|
+
# 0.2.4 (April 28, 2020)
|
8
|
+
- Delegate .publish to the .publisher for better understanding
|
9
|
+
|
10
|
+
# 0.2.3 (April 15, 2020)
|
11
|
+
- Improve helper names
|
12
|
+
- feat: perform manual sync with custom settings
|
13
|
+
- fix for "IO timeout when reading 7 bytes" error (Rabbit)
|
14
|
+
- style: do not print processed message when failed
|
15
|
+
- feat: retry delivery message when failed (RabbitMQ)
|
16
|
+
|
17
|
+
|
18
|
+
# 0.2.2 (March 27, 2020)
|
19
|
+
- fix default value for cattr_accessor in ror < 5.2
|
20
|
+
- add callbacks when publishing a message
|
21
|
+
|
22
|
+
# 0.2.1
|
23
|
+
- Add on demand model sync method
|
24
|
+
|
3
25
|
# 0.2.0
|
4
26
|
- Add apache kafka support
|
5
27
|
- Add Service interface for future references
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,64 +1,81 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pub_sub_model_sync (0.
|
4
|
+
pub_sub_model_sync (0.3.0)
|
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)
|
59
72
|
amq-protocol (~> 2.3, >= 2.3.0)
|
60
73
|
concurrent-ruby (1.1.6)
|
61
74
|
crass (1.0.6)
|
75
|
+
database_cleaner (1.8.4)
|
76
|
+
database_cleaner-active_record (1.8.0)
|
77
|
+
activerecord
|
78
|
+
database_cleaner (~> 1.8.0)
|
62
79
|
diff-lcs (1.3)
|
63
80
|
digest-crc (0.5.1)
|
64
81
|
erubi (1.9.0)
|
@@ -106,7 +123,7 @@ GEM
|
|
106
123
|
concurrent-ruby (~> 1.0)
|
107
124
|
jaro_winkler (1.5.4)
|
108
125
|
jwt (2.2.1)
|
109
|
-
loofah (2.
|
126
|
+
loofah (2.5.0)
|
110
127
|
crass (~> 1.0.2)
|
111
128
|
nokogiri (>= 1.5.9)
|
112
129
|
mail (2.7.1)
|
@@ -114,7 +131,7 @@ GEM
|
|
114
131
|
marcel (0.3.3)
|
115
132
|
mimemagic (~> 0.3.2)
|
116
133
|
memoist (0.16.2)
|
117
|
-
method_source (0.
|
134
|
+
method_source (1.0.0)
|
118
135
|
mimemagic (0.3.4)
|
119
136
|
mini_mime (1.0.2)
|
120
137
|
mini_portile2 (2.4.0)
|
@@ -132,30 +149,32 @@ GEM
|
|
132
149
|
rack (2.2.2)
|
133
150
|
rack-test (1.1.0)
|
134
151
|
rack (>= 1.0, < 3)
|
135
|
-
rails (
|
136
|
-
actioncable (=
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
152
|
+
rails (6.0.2.2)
|
153
|
+
actioncable (= 6.0.2.2)
|
154
|
+
actionmailbox (= 6.0.2.2)
|
155
|
+
actionmailer (= 6.0.2.2)
|
156
|
+
actionpack (= 6.0.2.2)
|
157
|
+
actiontext (= 6.0.2.2)
|
158
|
+
actionview (= 6.0.2.2)
|
159
|
+
activejob (= 6.0.2.2)
|
160
|
+
activemodel (= 6.0.2.2)
|
161
|
+
activerecord (= 6.0.2.2)
|
162
|
+
activestorage (= 6.0.2.2)
|
163
|
+
activesupport (= 6.0.2.2)
|
145
164
|
bundler (>= 1.3.0)
|
146
|
-
railties (=
|
165
|
+
railties (= 6.0.2.2)
|
147
166
|
sprockets-rails (>= 2.0.0)
|
148
167
|
rails-dom-testing (2.0.3)
|
149
168
|
activesupport (>= 4.2.0)
|
150
169
|
nokogiri (>= 1.6)
|
151
170
|
rails-html-sanitizer (1.3.0)
|
152
171
|
loofah (~> 2.3)
|
153
|
-
railties (
|
154
|
-
actionpack (=
|
155
|
-
activesupport (=
|
172
|
+
railties (6.0.2.2)
|
173
|
+
actionpack (= 6.0.2.2)
|
174
|
+
activesupport (= 6.0.2.2)
|
156
175
|
method_source
|
157
176
|
rake (>= 0.8.7)
|
158
|
-
thor (>= 0.
|
177
|
+
thor (>= 0.20.3, < 2.0)
|
159
178
|
rainbow (3.0.0)
|
160
179
|
rake (13.0.1)
|
161
180
|
rexml (3.2.4)
|
@@ -189,7 +208,7 @@ GEM
|
|
189
208
|
faraday (~> 0.9)
|
190
209
|
jwt (>= 1.5, < 3.0)
|
191
210
|
multi_json (~> 1.10)
|
192
|
-
sprockets (
|
211
|
+
sprockets (4.0.0)
|
193
212
|
concurrent-ruby (~> 1.0)
|
194
213
|
rack (> 1, < 3)
|
195
214
|
sprockets-rails (3.2.1)
|
@@ -199,12 +218,13 @@ GEM
|
|
199
218
|
sqlite3 (1.4.2)
|
200
219
|
thor (1.0.1)
|
201
220
|
thread_safe (0.3.6)
|
202
|
-
tzinfo (1.2.
|
221
|
+
tzinfo (1.2.7)
|
203
222
|
thread_safe (~> 0.1)
|
204
223
|
unicode-display_width (1.6.1)
|
205
224
|
websocket-driver (0.7.1)
|
206
225
|
websocket-extensions (>= 0.1.0)
|
207
226
|
websocket-extensions (0.1.4)
|
227
|
+
zeitwerk (2.3.0)
|
208
228
|
|
209
229
|
PLATFORMS
|
210
230
|
ruby
|
@@ -212,6 +232,7 @@ PLATFORMS
|
|
212
232
|
DEPENDENCIES
|
213
233
|
bundler
|
214
234
|
bunny
|
235
|
+
database_cleaner-active_record
|
215
236
|
google-cloud-pubsub
|
216
237
|
pub_sub_model_sync!
|
217
238
|
rake
|
@@ -221,4 +242,4 @@ DEPENDENCIES
|
|
221
242
|
sqlite3
|
222
243
|
|
223
244
|
BUNDLED WITH
|
224
|
-
2.
|
245
|
+
2.1.4
|
data/README.md
CHANGED
@@ -67,7 +67,7 @@ And then execute: $ bundle install
|
|
67
67
|
# attributes: name email age
|
68
68
|
class User < ActiveRecord::Base
|
69
69
|
include PubSubModelSync::PublisherConcern
|
70
|
-
ps_publish(%i[name email])
|
70
|
+
ps_publish(%i[id name email])
|
71
71
|
end
|
72
72
|
|
73
73
|
# App 2 (Subscriber)
|
@@ -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
|
```
|
@@ -93,26 +95,118 @@ PubSubModelSync::Publisher.new.publish_data(User, { msg: 'Hello' }, :greeting) #
|
|
93
95
|
class User < ActiveRecord::Base
|
94
96
|
self.table_name = 'publisher_users'
|
95
97
|
include PubSubModelSync::PublisherConcern
|
96
|
-
ps_publish(%i[name:full_name email], actions: %i[update], as_klass: 'Client'
|
98
|
+
ps_publish(%i[id:client_id name:full_name email], actions: %i[update], as_klass: 'Client')
|
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)
|
104
110
|
class User < ActiveRecord::Base
|
105
111
|
self.table_name = 'subscriber_users'
|
106
112
|
include PubSubModelSync::SubscriberConcern
|
107
|
-
ps_subscribe(%i[name], actions: %i[update], as_klass: 'Client', id:
|
113
|
+
ps_subscribe(%i[name], actions: %i[update], as_klass: 'Client', id: %i[client_id email])
|
108
114
|
ps_class_subscribe(:greeting, as_action: :custom_greeting, as_klass: 'CustomUser')
|
115
|
+
alias_attribute :full_name, :name
|
109
116
|
|
110
117
|
def self.greeting(data)
|
111
118
|
puts 'Class message called through custom_greeting'
|
112
119
|
end
|
120
|
+
|
121
|
+
# def self.ps_find_model(data, settings)
|
122
|
+
# where(email: data[:email], ...).first_or_initialize
|
123
|
+
# end
|
113
124
|
end
|
114
125
|
```
|
115
126
|
|
127
|
+
Note: Be careful with collision of names
|
128
|
+
```
|
129
|
+
class User
|
130
|
+
# ps_publish %i[name_data:name name:key] # key will be replaced with name_data
|
131
|
+
ps_publish %i[name_data:name key_data:key] # use alias to avoid collision
|
132
|
+
|
133
|
+
def key_data
|
134
|
+
name
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
## API
|
140
|
+
### Subscribers
|
141
|
+
- Permit to configure class level listeners
|
142
|
+
```ps_class_subscribe(action_name, as_action: nil, as_klass: nil)```
|
143
|
+
* as_action: (Optional) Source method name
|
144
|
+
* as_klass: (Optional) Source class name
|
145
|
+
|
146
|
+
- Permit to configure instance level listeners (CRUD)
|
147
|
+
```ps_subscribe(attrs, as_klass: nil, actions: nil, id: nil)```
|
148
|
+
* attrs: (Array/Required) Array of all attributes to be synced
|
149
|
+
* as_klass: (String/Optional) Source class name (Instead of the model class name, will use this value)
|
150
|
+
* actions: (Array/Optional, default: create/update/destroy) permit to customize action names
|
151
|
+
* id: (Sym|Array/Optional, default: id) Attr identifier(s) to find the corresponding model
|
152
|
+
|
153
|
+
- Permit to configure a custom model finder
|
154
|
+
```ps_find_model(data, settings)```
|
155
|
+
* data: (Hash) Data received from sync
|
156
|
+
* settings: (Hash(:klass, :action)) Class and action name from sync
|
157
|
+
Must return an existent or a new model object
|
158
|
+
|
159
|
+
- Get crud subscription configured for the class
|
160
|
+
```User.ps_subscriber(action_name)```
|
161
|
+
* action_name (default :create, :sym): can be :create, :update, :destroy
|
162
|
+
|
163
|
+
- Inspect all configured listeners
|
164
|
+
```PubSubModelSync::Config.listeners```
|
165
|
+
|
166
|
+
### Publishers
|
167
|
+
- Permit to configure crud publishers
|
168
|
+
```ps_publish(attrs, actions: nil, as_klass: nil)```
|
169
|
+
* attrs: (Array/Required) Array of attributes to be published
|
170
|
+
* actions: (Array/Optional, default: create/update/destroy) permit to customize action names
|
171
|
+
* as_klass: (String/Optional) Output class name (Instead of the model class name, will use this value)
|
172
|
+
|
173
|
+
- Permit to cancel sync called after create/update/destroy (Before initializing sync service)
|
174
|
+
```model.ps_skip_callback?(action)```
|
175
|
+
Note: Return true to cancel sync
|
176
|
+
|
177
|
+
- Callback called before preparing data for sync (Permit to stop sync)
|
178
|
+
```model.ps_skip_sync?(action)```
|
179
|
+
Note: return true to cancel sync
|
180
|
+
|
181
|
+
- Callback called before sync (After preparing data)
|
182
|
+
```model.ps_before_sync(action, data_to_deliver)```
|
183
|
+
Note: If the method returns ```:cancel```, the sync will be stopped (message will not be published)
|
184
|
+
|
185
|
+
- Callback called after sync
|
186
|
+
```model.ps_after_sync(action, data_delivered)```
|
187
|
+
|
188
|
+
- Perform sync on demand (:create, :update, :destroy):
|
189
|
+
The target model will receive a notification to perform the indicated action
|
190
|
+
```my_model.ps_perform_sync(action_name, custom_settings = {})```
|
191
|
+
* custom_settings: override default settings defined for action_name ({ attrs: [], as_klass: nil })
|
192
|
+
|
193
|
+
- Publish a class level notification:
|
194
|
+
```User.ps_class_publish(data, action: action_name, as_klass: custom_klass_name)```
|
195
|
+
Target class ```User.action_name``` will be called when message is received
|
196
|
+
* data: (required, :hash) message value to deliver
|
197
|
+
* action_name: (required, :sim) Action name
|
198
|
+
* as_klass: (optional, :string) Custom class name (Default current model name)
|
199
|
+
|
200
|
+
- Publish a class level notification (Same as above: on demand call)
|
201
|
+
```PubSubModelSync::Publisher.new.publish_data(Klass_name, data, action_name)```
|
202
|
+
* klass_name: (required, Class) same class name as defined in ps_class_subscribe(...)
|
203
|
+
* data: (required, :hash) message value to deliver
|
204
|
+
* action_name: (required, :sim) same action name as defined in ps_class_subscribe(...)
|
205
|
+
|
206
|
+
- Get crud publisher configured for the class
|
207
|
+
```User.ps_publisher(action_name)```
|
208
|
+
* action_name (default :create, :sym): can be :create, :update, :destroy
|
209
|
+
|
116
210
|
## Testing with RSpec
|
117
211
|
- Config: (spec/rails_helper.rb)
|
118
212
|
```ruby
|
@@ -144,12 +238,10 @@ end
|
|
144
238
|
# Subscriber
|
145
239
|
it 'receive model message' do
|
146
240
|
action = :create
|
147
|
-
data = { name: 'name' }
|
148
|
-
|
149
|
-
attrs = PubSubModelSync::Publisher.build_attrs('User', action, user_id)
|
150
|
-
publisher = PubSubModelSync::MessageProcessor.new(data, 'User', action, id: user_id)
|
241
|
+
data = { name: 'name', id: 999 }
|
242
|
+
publisher = PubSubModelSync::MessageProcessor.new(data, 'User', action)
|
151
243
|
publisher.process
|
152
|
-
expect(User.where(id:
|
244
|
+
expect(User.where(id: data[:id]).any?).to be_truth
|
153
245
|
end
|
154
246
|
|
155
247
|
it 'receive class message' do
|
@@ -178,15 +270,6 @@ end
|
|
178
270
|
expect_any_instance_of(publisher).to receive(:publish_data).with('User', data, action)
|
179
271
|
end
|
180
272
|
```
|
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
273
|
|
191
274
|
## Contributing
|
192
275
|
|
@@ -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
|
@@ -2,21 +2,23 @@
|
|
2
2
|
|
3
3
|
module PubSubModelSync
|
4
4
|
class MessageProcessor
|
5
|
-
attr_accessor :data, :
|
5
|
+
attr_accessor :data, :settings, :message_id
|
6
6
|
|
7
7
|
# @param data (Hash): any hash value to deliver
|
8
|
-
|
9
|
-
def initialize(data, klass, action, settings = {})
|
8
|
+
def initialize(data, klass, action)
|
10
9
|
@data = data
|
11
|
-
@settings =
|
12
|
-
@
|
10
|
+
@settings = { klass: klass, action: action }
|
11
|
+
@message_id = [klass, action, Time.current.to_i].join('-')
|
13
12
|
end
|
14
13
|
|
15
14
|
def process
|
16
|
-
|
15
|
+
@failed = false
|
16
|
+
log "processing message: #{[data, settings]}"
|
17
17
|
listeners = filter_listeners
|
18
|
-
|
19
|
-
|
18
|
+
return log 'Skipped: No listeners' unless listeners.any?
|
19
|
+
|
20
|
+
eval_message(listeners)
|
21
|
+
log 'processed message' unless @failed
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
@@ -36,12 +38,13 @@ module PubSubModelSync
|
|
36
38
|
model_class.send(listener[:action], data)
|
37
39
|
rescue => e
|
38
40
|
log("Error listener (#{listener}): #{e.message}", :error)
|
41
|
+
@failed = true
|
39
42
|
end
|
40
43
|
|
41
44
|
# support for: create, update, destroy
|
42
45
|
def call_listener(listener)
|
43
46
|
model = find_model(listener)
|
44
|
-
if
|
47
|
+
if settings[:action].to_sym == :destroy
|
45
48
|
model.destroy!
|
46
49
|
else
|
47
50
|
populate_model(model, listener)
|
@@ -49,13 +52,22 @@ module PubSubModelSync
|
|
49
52
|
end
|
50
53
|
rescue => e
|
51
54
|
log("Error listener (#{listener}): #{e.message}", :error)
|
55
|
+
@failed = true
|
52
56
|
end
|
53
57
|
|
54
58
|
def find_model(listener)
|
55
59
|
model_class = listener[:klass].constantize
|
56
|
-
|
57
|
-
|
58
|
-
|
60
|
+
if model_class.respond_to?(:ps_find_model)
|
61
|
+
return model_class.ps_find_model(data, settings)
|
62
|
+
end
|
63
|
+
|
64
|
+
model_class.where(model_identifiers(listener)).first_or_initialize
|
65
|
+
end
|
66
|
+
|
67
|
+
def model_identifiers(listener)
|
68
|
+
identifiers = listener[:settings][:id]
|
69
|
+
identifiers = [identifiers] unless identifiers.is_a?(Array)
|
70
|
+
identifiers.map { |key| [key, data[key.to_sym]] }.to_h
|
59
71
|
end
|
60
72
|
|
61
73
|
def populate_model(model, listener)
|
@@ -68,13 +80,13 @@ module PubSubModelSync
|
|
68
80
|
def filter_listeners
|
69
81
|
listeners = PubSubModelSync::Config.listeners
|
70
82
|
listeners.select do |listener|
|
71
|
-
listener[:as_klass].to_s ==
|
72
|
-
listener[:as_action].to_s ==
|
83
|
+
listener[:as_klass].to_s == settings[:klass].to_s &&
|
84
|
+
listener[:as_action].to_s == settings[:action].to_s
|
73
85
|
end
|
74
86
|
end
|
75
87
|
|
76
88
|
def log(message, kind = :info)
|
77
|
-
PubSubModelSync::Config.log "#{
|
89
|
+
PubSubModelSync::Config.log "(ID: #{message_id}) #{message}", kind
|
78
90
|
end
|
79
91
|
end
|
80
92
|
end
|
@@ -3,30 +3,33 @@
|
|
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
|
-
# @param
|
16
|
-
def publish_model(model, action,
|
17
|
-
|
17
|
+
# @param custom_settings (Hash): { attrs: [], as_klass: nil }
|
18
|
+
def publish_model(model, action, custom_settings = {})
|
19
|
+
return if model.ps_skip_sync?(action)
|
20
|
+
|
21
|
+
settings = model.class.ps_publisher(action).merge(custom_settings)
|
18
22
|
attributes = build_model_attrs(model, action, settings)
|
19
|
-
data =
|
20
|
-
|
21
|
-
|
23
|
+
data = build_model_data(model, settings[:attrs])
|
24
|
+
res_before = model.ps_before_sync(action, data)
|
25
|
+
return if res_before == :cancel
|
26
|
+
|
27
|
+
publish(data.symbolize_keys, attributes)
|
28
|
+
model.ps_after_sync(action, data)
|
22
29
|
end
|
23
30
|
|
24
|
-
def self.build_attrs(klass, action
|
25
|
-
{
|
26
|
-
klass: klass.to_s,
|
27
|
-
action: action.to_sym,
|
28
|
-
id: id
|
29
|
-
}
|
31
|
+
def self.build_attrs(klass, action)
|
32
|
+
{ klass: klass.to_s, action: action.to_sym }
|
30
33
|
end
|
31
34
|
|
32
35
|
private
|
@@ -44,8 +47,7 @@ module PubSubModelSync
|
|
44
47
|
|
45
48
|
def build_model_attrs(model, action, settings)
|
46
49
|
as_klass = (settings[:as_klass] || model.class.name).to_s
|
47
|
-
|
48
|
-
self.class.build_attrs(as_klass, action, id_val)
|
50
|
+
self.class.build_attrs(as_klass, action)
|
49
51
|
end
|
50
52
|
|
51
53
|
def log(msg)
|
@@ -6,34 +6,55 @@ 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 }
|
27
|
+
def ps_perform_sync(action = :create, custom_settings = {})
|
28
|
+
service = self.class.ps_publisher_service
|
29
|
+
model_settings = self.class.ps_publisher(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)
|
16
|
-
|
17
|
-
|
18
|
-
actions = settings.delete(:actions) || %i[create update destroy]
|
34
|
+
# Permit to configure to publish crud actions (:create, :update, :destroy)
|
35
|
+
def ps_publish(attrs, actions: %i[create update destroy], as_klass: nil)
|
36
|
+
as_klass ||= name
|
19
37
|
actions.each do |action|
|
20
|
-
info =
|
38
|
+
info = { klass: name, action: action, attrs: attrs,
|
39
|
+
as_klass: as_klass }
|
21
40
|
PubSubModelSync::Config.publishers << info
|
22
41
|
ps_register_callback(action.to_sym, info)
|
23
42
|
end
|
24
43
|
end
|
25
44
|
|
26
|
-
|
27
|
-
PubSubModelSync::Config.publishers.select do |listener|
|
28
|
-
listener[:klass] == name && listener[:action] == action
|
29
|
-
end.last
|
30
|
-
end
|
31
|
-
|
45
|
+
# On demand class level publisher
|
32
46
|
def ps_class_publish(data, action:, as_klass: nil)
|
33
47
|
as_klass = (as_klass || name).to_s
|
34
48
|
ps_publisher_service.publish_data(as_klass, data, action.to_sym)
|
35
49
|
end
|
36
50
|
|
51
|
+
# Publisher info for specific action
|
52
|
+
def ps_publisher(action = :create)
|
53
|
+
PubSubModelSync::Config.publishers.find do |listener|
|
54
|
+
listener[:klass] == name && listener[:action] == action
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
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
|
@@ -18,11 +18,11 @@ module PubSubModelSync
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
# @param payload (String JSON): '{"data":{},"attributes":{..}}'
|
21
|
+
# @param payload (String JSON): '{"data":{}, "attributes":{..}}'
|
22
22
|
# refer: PubSubModelSync::Publisher (.publish_model | .publish_data)
|
23
23
|
def perform_message(payload)
|
24
24
|
data, attrs = parse_message_payload(payload)
|
25
|
-
args = [data, attrs[:klass], attrs[:action]
|
25
|
+
args = [data, attrs[:klass], attrs[:action]]
|
26
26
|
PubSubModelSync::MessageProcessor.new(*args).process
|
27
27
|
end
|
28
28
|
|
@@ -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
|
@@ -7,11 +7,9 @@ module PubSubModelSync
|
|
7
7
|
end
|
8
8
|
|
9
9
|
module ClassMethods
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
actions = settings.delete(:actions) || %i[create update destroy]
|
14
|
-
settings = settings.merge(attrs: attrs)
|
10
|
+
def ps_subscribe(attrs, as_klass: nil, actions: nil, id: :id)
|
11
|
+
actions ||= %i[create update destroy]
|
12
|
+
settings = { attrs: attrs, id: id }
|
15
13
|
actions.each do |action|
|
16
14
|
add_ps_subscriber(as_klass, action, action, false, settings)
|
17
15
|
end
|
@@ -22,13 +20,14 @@ module PubSubModelSync
|
|
22
20
|
end
|
23
21
|
|
24
22
|
def ps_subscriber(action = :create)
|
25
|
-
PubSubModelSync::Config.listeners.
|
23
|
+
PubSubModelSync::Config.listeners.find do |listener|
|
26
24
|
listener[:klass] == name && listener[:action] == action
|
27
|
-
end
|
25
|
+
end
|
28
26
|
end
|
29
27
|
|
30
28
|
private
|
31
29
|
|
30
|
+
# @param settings (Hash): { id:, attrs: }
|
32
31
|
def add_ps_subscriber(as_klass, action, as_action, direct_mode, settings)
|
33
32
|
listener = {
|
34
33
|
klass: name,
|
@@ -38,7 +37,7 @@ module PubSubModelSync
|
|
38
37
|
direct_mode: direct_mode,
|
39
38
|
settings: settings
|
40
39
|
}
|
41
|
-
PubSubModelSync::Config.listeners
|
40
|
+
PubSubModelSync::Config.listeners.push(listener) && listener
|
42
41
|
end
|
43
42
|
end
|
44
43
|
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.3.0
|
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-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -101,10 +101,19 @@ executables: []
|
|
101
101
|
extensions: []
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
|
+
- ".github/workflows/ruby.yml"
|
104
105
|
- ".gitignore"
|
106
|
+
- ".idea/.gitignore"
|
107
|
+
- ".idea/.rakeTasks"
|
108
|
+
- ".idea/codeStyles/codeStyleConfig.xml"
|
109
|
+
- ".idea/encodings.xml"
|
110
|
+
- ".idea/inspectionProfiles/Project_Default.xml"
|
111
|
+
- ".idea/misc.xml"
|
112
|
+
- ".idea/modules.xml"
|
113
|
+
- ".idea/pub_sub_model_sync.iml"
|
114
|
+
- ".idea/vcs.xml"
|
105
115
|
- ".rspec"
|
106
116
|
- ".rubocop.yml"
|
107
|
-
- ".travis.yml"
|
108
117
|
- CHANGELOG.md
|
109
118
|
- CODE_OF_CONDUCT.md
|
110
119
|
- Gemfile
|
@@ -155,8 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
164
|
- !ruby/object:Gem::Version
|
156
165
|
version: '0'
|
157
166
|
requirements: []
|
158
|
-
|
159
|
-
rubygems_version: 2.7.7
|
167
|
+
rubygems_version: 3.0.8
|
160
168
|
signing_key:
|
161
169
|
specification_version: 4
|
162
170
|
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
|