pub_sub_model_sync 0.2.2 → 0.4.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.
@@ -18,11 +18,11 @@ module PubSubModelSync
18
18
 
19
19
  private
20
20
 
21
- # @param payload (String JSON): '{"data":{},"attributes":{..}}'
22
- # refer: PubSubModelSync::Publisher (.publish_model | .publish_data)
21
+ # @param payload (String JSON): '{"data":{}, "attributes":{..}}'
22
+ # refer: PubSubModelSync::MessagePublisher(.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], attrs]
25
+ args = [data, attrs[:klass], attrs[:action]]
26
26
  PubSubModelSync::MessageProcessor.new(*args).process
27
27
  end
28
28
 
@@ -30,9 +30,11 @@ module PubSubModelSync
30
30
 
31
31
  def publish(data, attributes)
32
32
  log("Publishing message: #{[data, attributes]}")
33
-
34
33
  payload = { data: data, attributes: attributes }.to_json
35
34
  topic.publish(payload, { SERVICE_KEY => true })
35
+ rescue => e
36
+ info = [data, attributes, e.message, e.backtrace]
37
+ log("Error publishing: #{info}", :error)
36
38
  end
37
39
 
38
40
  def stop
@@ -19,7 +19,8 @@ module PubSubModelSync
19
19
  log('Listener starting...')
20
20
  subscribe_to_queue
21
21
  log('Listener started')
22
- queue.subscribe(block: true, manual_ack: false, &method(:process_message))
22
+ queue.subscribe(subscribe_settings, &method(:process_message))
23
+ loop { sleep 5 }
23
24
  rescue PubSubModelSync::Runner::ShutDown
24
25
  raise
25
26
  rescue => e
@@ -28,9 +29,12 @@ module PubSubModelSync
28
29
 
29
30
  def publish(data, attributes)
30
31
  log("Publishing: #{[data, attributes]}")
31
- subscribe_to_queue
32
- payload = { data: data, attributes: attributes }
33
- topic.publish(payload.to_json, message_settings)
32
+ deliver_data(data, attributes)
33
+ # TODO: max retry
34
+ rescue Timeout::Error => e
35
+ log("Error publishing (retrying....): #{e.message}", :error)
36
+ initialize
37
+ retry
34
38
  rescue => e
35
39
  info = [data, attributes, e.message, e.backtrace]
36
40
  log("Error publishing: #{info}", :error)
@@ -47,6 +51,10 @@ module PubSubModelSync
47
51
  { routing_key: queue.name, type: SERVICE_KEY }
48
52
  end
49
53
 
54
+ def subscribe_settings
55
+ { manual_ack: false }
56
+ end
57
+
50
58
  def process_message(_delivery_info, meta_info, payload)
51
59
  return unless meta_info[:type] == SERVICE_KEY
52
60
 
@@ -72,5 +80,16 @@ module PubSubModelSync
72
80
  def log(msg, kind = :info)
73
81
  config.log("Rabbit Service ==> #{msg}", kind)
74
82
  end
83
+
84
+ def deliver_data(data, attributes)
85
+ subscribe_to_queue
86
+ payload = { data: data, attributes: attributes }
87
+ topic.publish(payload.to_json, message_settings)
88
+
89
+ # Ugly fix: "IO timeout when reading 7 bytes"
90
+ # https://stackoverflow.com/questions/39039129/rabbitmq-timeouterror-io-timeout-when-reading-7-bytes
91
+ channel.close
92
+ service.close
93
+ end
75
94
  end
76
95
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PubSubModelSync
4
+ class Subscriber
5
+ attr_accessor :klass, :action, :attrs, :settings
6
+
7
+ # @param settings: (Hash) { id: :id, direct_mode: false,
8
+ # from_klass: klass, from_action: action }
9
+ def initialize(klass, action, attrs: nil, settings: {})
10
+ def_settings = { id: :id, direct_mode: false,
11
+ from_klass: klass, from_action: action }
12
+ @klass = klass
13
+ @action = action
14
+ @attrs = attrs
15
+ @settings = def_settings.merge(settings)
16
+ end
17
+
18
+ def eval_message(message)
19
+ if settings[:direct_mode]
20
+ run_class_message(message)
21
+ else
22
+ run_model_message(message)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def run_class_message(message)
29
+ model_class = klass.constantize
30
+ model_class.send(action, message)
31
+ end
32
+
33
+ # support for: create, update, destroy
34
+ def run_model_message(message)
35
+ model = find_model(message)
36
+ if action == :destroy
37
+ model.destroy!
38
+ else
39
+ populate_model(model, message)
40
+ model.save!
41
+ end
42
+ end
43
+
44
+ def find_model(message)
45
+ model_class = klass.constantize
46
+ if model_class.respond_to?(:ps_find_model)
47
+ return model_class.ps_find_model(message)
48
+ end
49
+
50
+ model_class.where(model_identifiers(message)).first_or_initialize
51
+ end
52
+
53
+ def model_identifiers(message)
54
+ identifiers = Array(settings[:id])
55
+ identifiers.map { |key| [key, message[key.to_sym]] }.to_h
56
+ end
57
+
58
+ def populate_model(model, message)
59
+ values = message.slice(*attrs)
60
+ values.each do |attr, value|
61
+ model.send("#{attr}=", value)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -7,38 +7,34 @@ module PubSubModelSync
7
7
  end
8
8
 
9
9
  module ClassMethods
10
- # @param settings (Hash): { as_klass: nil, actions: nil, id: nil }
11
- def ps_subscribe(attrs, settings = {})
12
- as_klass = (settings[:as_klass] || name).to_s
13
- actions = settings.delete(:actions) || %i[create update destroy]
14
- settings = settings.merge(attrs: attrs)
10
+ def ps_subscribe(attrs, actions: nil, from_klass: name, id: :id)
11
+ settings = { id: id, from_klass: from_klass }
12
+ actions ||= %i[create update destroy]
15
13
  actions.each do |action|
16
- add_ps_subscriber(as_klass, action, action, false, settings)
14
+ add_ps_subscriber(action, attrs, settings)
17
15
  end
18
16
  end
19
17
 
20
- def ps_class_subscribe(action, as_action: nil, as_klass: nil)
21
- add_ps_subscriber(as_klass, action, as_action, true, {})
18
+ def ps_class_subscribe(action, from_action: nil, from_klass: nil)
19
+ settings = { direct_mode: true }
20
+ settings[:from_action] = from_action if from_action
21
+ settings[:from_klass] = from_klass if from_klass
22
+ add_ps_subscriber(action, nil, settings)
22
23
  end
23
24
 
24
25
  def ps_subscriber(action = :create)
25
- PubSubModelSync::Config.listeners.select do |listener|
26
- listener[:klass] == name && listener[:action] == action
27
- end.last
26
+ PubSubModelSync::Config.subscribers.find do |subscriber|
27
+ subscriber.klass == name && subscriber.action == action
28
+ end
28
29
  end
29
30
 
30
31
  private
31
32
 
32
- def add_ps_subscriber(as_klass, action, as_action, direct_mode, settings)
33
- listener = {
34
- klass: name,
35
- as_klass: (as_klass || name).to_s,
36
- action: action.to_sym,
37
- as_action: (as_action || action).to_sym,
38
- direct_mode: direct_mode,
39
- settings: settings
40
- }
41
- PubSubModelSync::Config.listeners << listener
33
+ # @param settings (Hash): refer to PubSubModelSync::Subscriber.settings
34
+ def add_ps_subscriber(action, attrs, settings = {})
35
+ klass = PubSubModelSync::Subscriber
36
+ subscriber = klass.new(name, action, attrs: attrs, settings: settings)
37
+ PubSubModelSync::Config.subscribers.push(subscriber) && subscriber
42
38
  end
43
39
  end
44
40
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PubSubModelSync
4
- VERSION = '0.2.2'
4
+ VERSION = '0.4.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pub_sub_model_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.4.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-03-28 00:00:00.000000000 Z
11
+ date: 2020-05-06 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
@@ -118,6 +127,7 @@ files:
118
127
  - lib/pub_sub_model_sync/config.rb
119
128
  - lib/pub_sub_model_sync/connector.rb
120
129
  - lib/pub_sub_model_sync/message_processor.rb
130
+ - lib/pub_sub_model_sync/message_publisher.rb
121
131
  - lib/pub_sub_model_sync/mock_google_service.rb
122
132
  - lib/pub_sub_model_sync/mock_kafka_service.rb
123
133
  - lib/pub_sub_model_sync/mock_rabbit_service.rb
@@ -129,6 +139,7 @@ files:
129
139
  - lib/pub_sub_model_sync/service_google.rb
130
140
  - lib/pub_sub_model_sync/service_kafka.rb
131
141
  - lib/pub_sub_model_sync/service_rabbit.rb
142
+ - lib/pub_sub_model_sync/subscriber.rb
132
143
  - lib/pub_sub_model_sync/subscriber_concern.rb
133
144
  - lib/pub_sub_model_sync/tasks/worker.rake
134
145
  - lib/pub_sub_model_sync/version.rb
@@ -155,8 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
166
  - !ruby/object:Gem::Version
156
167
  version: '0'
157
168
  requirements: []
158
- rubyforge_project:
159
- rubygems_version: 2.7.7
169
+ rubygems_version: 3.0.8
160
170
  signing_key:
161
171
  specification_version: 4
162
172
  summary: Permit to sync models between apps through pub/sub
@@ -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