pub_sub_model_sync 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -0
- data/Gemfile.lock +1 -1
- data/README.md +7 -2
- data/lib/pub_sub_model_sync/config.rb +1 -0
- data/lib/pub_sub_model_sync/message_publisher.rb +5 -2
- data/lib/pub_sub_model_sync/payload.rb +19 -1
- data/lib/pub_sub_model_sync/payload_cache_optimizer.rb +50 -0
- data/lib/pub_sub_model_sync/service_base.rb +1 -1
- data/lib/pub_sub_model_sync/version.rb +1 -1
- data/lib/pub_sub_model_sync.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1740843df35081aaeb35e2be5c1c27cf1ff4d219af0bcf9ae4394495ab8bba5e
|
4
|
+
data.tar.gz: ed506905c6b29b554f4a1cd100ddf4c8df2bf0a99590eb26901fae8feef862ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bff308ce421ae321d2a9e7b53df194d3678e5f6103eb4f2048d4ed064302c042fb7768f96a3c639190b8d452a0636fded9e72394a5ffe4731b4e24ba0b2f5b53
|
7
|
+
data.tar.gz: e60c4c78c5fbde7c40d68adb1ed029d74bb10d1759a27682850aae6015c84f938cbccccaadc976878afa26d97621d360937cdeb5cc028b2393facb12fa0d4831
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -313,10 +313,15 @@ Any notification before delivering is transformed as a Payload for a better port
|
|
313
313
|
* `headers`: (Hash) Notification settings that defines how the notification will be processed or delivered.
|
314
314
|
- `ordering_key`: (String, optional): notifications with the same `ordering_key` are processed in the same order they were delivered, default: `<model.class.name>/<model.id>` when instance notification and `klass_name` when class notification.
|
315
315
|
Note: Final `ordering_key` is calculated as: `payload.headers[:forced_ordering_key] || current_transaction&.key || payload.headers[:ordering_key]`
|
316
|
-
- `internal_key`: (String, optional) Internal identifier of the payload, default: `<model.class.name>/<action>/<model.id>` when model notification and `<klass_name>/<action>` when class notification (Useful for caching techniques).
|
317
316
|
- `topic_name`: (String|Array<String>, optional): Specific topic name where to deliver the notification (default `PubSubModelSync::Config.topic_name`).
|
318
317
|
- `forced_ordering_key`: (String, optional): Overrides `ordering_key` with the provided value even withing transactions. Default `nil`.
|
319
|
-
- `
|
318
|
+
- `cache` (Boolean | Hash, Default false) Cache settings
|
319
|
+
- `true`: Skip publishing similar payloads
|
320
|
+
- `Hash<required: Array<Symbol>>`: Same as `true` and enables payload optimization to exclude unchanged non important attributes. Sample: `{ required: %i[id email] }`
|
321
|
+
|
322
|
+
** Read ONLY **
|
323
|
+
- `internal_key`: Internal identifier of the payload, default: `<model.class.name>/<action>/<model.id>` when model notification and `<klass_name>/<action>` when class notification (Useful for caching techniques).
|
324
|
+
- `app_key`: (Auto calculated): Name of the application who delivered the notification.
|
320
325
|
- `uuid`: (Auto calculated): Unique notification identifier (Very useful when debugging).
|
321
326
|
Note: To reduce Payload size, some header info are not delivered (Enable debug mode to deliver all payload info).
|
322
327
|
|
@@ -9,6 +9,7 @@ module PubSubModelSync
|
|
9
9
|
cattr_accessor(:debug) { false }
|
10
10
|
cattr_accessor :logger # LoggerInst
|
11
11
|
cattr_accessor(:transactions_max_buffer) { 1 }
|
12
|
+
cattr_accessor(:skip_cache) { false }
|
12
13
|
|
13
14
|
cattr_accessor(:on_before_processing) { ->(_payload, _info) {} } # return :cancel to skip
|
14
15
|
cattr_accessor(:on_success_processing) { ->(_payload, _info) {} }
|
@@ -98,8 +98,11 @@ module PubSubModelSync
|
|
98
98
|
private
|
99
99
|
|
100
100
|
def ensure_publish(payload)
|
101
|
-
|
102
|
-
|
101
|
+
cache_klass = PubSubModelSync::PayloadCacheOptimizer
|
102
|
+
cancelled = payload.cache_settings ? cache_klass.new(payload).call == :already_sent : false
|
103
|
+
cancelled ||= config.on_before_publish.call(payload) == :cancel
|
104
|
+
log_msg = "Publish cancelled by config.on_before_publish or cache checker: #{[payload]}"
|
105
|
+
log(log_msg) if config.debug && cancelled
|
103
106
|
!cancelled
|
104
107
|
end
|
105
108
|
|
@@ -19,9 +19,17 @@ module PubSubModelSync
|
|
19
19
|
# <klass>: when class message
|
20
20
|
# <klass/id>: when model message
|
21
21
|
# topic_name (String|Array<String>): Specific topic name to be used when delivering the
|
22
|
-
# message (default
|
22
|
+
# message (default Config.topic_name)
|
23
23
|
# forced_ordering_key (String, optional): Will force to use this value as the ordering_key,
|
24
24
|
# even withing transactions. Default nil.
|
25
|
+
# cache (Boolean | Hash, Default false) Cache settings
|
26
|
+
# true: Skip publishing similar payloads
|
27
|
+
# Hash<required: Array<Symbol>>: Same as true and enables payload optimization to exclude
|
28
|
+
# unchanged non important attributes. Sample: { required: %i[id email] }
|
29
|
+
# --- READ ONLY ----
|
30
|
+
# app_key: (string) Subscriber-Key of the application who delivered the notification
|
31
|
+
# internal_key: (String) "<klass>/<action>"
|
32
|
+
# uuid: Unique notification identifier
|
25
33
|
def initialize(data, info, headers = {})
|
26
34
|
@data = data.deep_symbolize_keys
|
27
35
|
@info = info.deep_symbolize_keys
|
@@ -75,6 +83,16 @@ module PubSubModelSync
|
|
75
83
|
klass.publish(self)
|
76
84
|
end
|
77
85
|
|
86
|
+
# @param attr_keys (Array<Symbol>) List of attributes to be excluded from payload
|
87
|
+
def exclude_data_attrs(attr_keys)
|
88
|
+
@data = data.except(*attr_keys)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Attributes to always be delivered after cache optimization
|
92
|
+
def cache_settings
|
93
|
+
headers[:cache]
|
94
|
+
end
|
95
|
+
|
78
96
|
# convert payload data into Payload
|
79
97
|
# @param data [Hash]: payload data (:data, :info, :headers)
|
80
98
|
def self.from_payload_data(data)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PubSubModelSync
|
4
|
+
class PayloadCacheOptimizer < PubSubModelSync::Base
|
5
|
+
# Optimizes payload data to deliver only the required ones and the changed ones and thus avoid
|
6
|
+
# delivering unnecessary notifications.
|
7
|
+
# Uses Rails.cache to retrieve previous delivered data.
|
8
|
+
attr_reader :payload, :required_attrs, :cache_key
|
9
|
+
|
10
|
+
# @param payload (Payload)
|
11
|
+
def initialize(payload)
|
12
|
+
@payload = payload
|
13
|
+
@cache_key = "pubsub/#{payload.headers[:internal_key]}/#{payload.headers[:topic_name]}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return (:already_sent|Payload)
|
17
|
+
def call
|
18
|
+
backup_data = payload.data.clone
|
19
|
+
return payload if cache_disabled?
|
20
|
+
return :already_sent if previous_payload_data == payload.data
|
21
|
+
|
22
|
+
optimize_payload if optimization_enabled?
|
23
|
+
Rails.cache.write(cache_key, backup_data, expires_in: 1.week)
|
24
|
+
payload
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def optimization_enabled?
|
30
|
+
previous_payload_data && payload.cache_settings.is_a?(Hash)
|
31
|
+
end
|
32
|
+
|
33
|
+
def cache_disabled?
|
34
|
+
res = config.skip_cache || Rails.cache.nil?
|
35
|
+
log("Skipping cache, it was disabled: #{[payload]}") if res && debug?
|
36
|
+
res
|
37
|
+
end
|
38
|
+
|
39
|
+
def previous_payload_data
|
40
|
+
@previous_payload_data ||= Rails.cache.read(cache_key)
|
41
|
+
end
|
42
|
+
|
43
|
+
def optimize_payload # rubocop:disable Metrics/AbcSize
|
44
|
+
changed_keys = Hash[(payload.data.to_a - previous_payload_data.to_a)].keys
|
45
|
+
invalid_keys = payload.data.keys - (changed_keys + payload.cache_settings[:required])
|
46
|
+
log("Excluding non changed attributes: #{invalid_keys} from: #{payload.inspect}") if debug?
|
47
|
+
payload.exclude_data_attrs(invalid_keys)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -24,7 +24,7 @@ module PubSubModelSync
|
|
24
24
|
# @return (String): Json Format
|
25
25
|
def encode_payload(payload)
|
26
26
|
data = payload.to_h
|
27
|
-
not_important_keys = %i[forced_ordering_key]
|
27
|
+
not_important_keys = %i[forced_ordering_key cache]
|
28
28
|
reduce_payload_size = !config.debug
|
29
29
|
data[:headers].except!(*not_important_keys) if reduce_payload_size
|
30
30
|
data.to_json
|
data/lib/pub_sub_model_sync.rb
CHANGED
@@ -16,6 +16,7 @@ require 'pub_sub_model_sync/message_processor'
|
|
16
16
|
require 'pub_sub_model_sync/run_subscriber'
|
17
17
|
|
18
18
|
require 'pub_sub_model_sync/payload_builder'
|
19
|
+
require 'pub_sub_model_sync/payload_cache_optimizer'
|
19
20
|
require 'pub_sub_model_sync/subscriber'
|
20
21
|
|
21
22
|
require 'pub_sub_model_sync/service_base'
|
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: 1.
|
4
|
+
version: 1.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: 2022-02
|
11
|
+
date: 2022-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- lib/pub_sub_model_sync/mock_rabbit_service.rb
|
120
120
|
- lib/pub_sub_model_sync/payload.rb
|
121
121
|
- lib/pub_sub_model_sync/payload_builder.rb
|
122
|
+
- lib/pub_sub_model_sync/payload_cache_optimizer.rb
|
122
123
|
- lib/pub_sub_model_sync/publisher_concern.rb
|
123
124
|
- lib/pub_sub_model_sync/railtie.rb
|
124
125
|
- lib/pub_sub_model_sync/run_subscriber.rb
|