ruby_event_store-outbox 0.0.8 → 0.0.13
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/lib/generators/ruby_event_store/outbox/templates/create_event_store_outbox_template.rb +8 -0
- data/lib/ruby_event_store/outbox.rb +1 -0
- data/lib/ruby_event_store/outbox/cli.rb +3 -3
- data/lib/ruby_event_store/outbox/consumer.rb +124 -34
- data/lib/ruby_event_store/outbox/consumer_process.rb +6 -0
- data/lib/ruby_event_store/outbox/fetch_specification.rb +13 -0
- data/lib/ruby_event_store/outbox/metrics.rb +2 -3
- data/lib/ruby_event_store/outbox/metrics/influx.rb +20 -6
- data/lib/ruby_event_store/outbox/metrics/null.rb +4 -1
- data/lib/ruby_event_store/outbox/record.rb +88 -0
- data/lib/ruby_event_store/outbox/sidekiq_processor.rb +44 -0
- data/lib/ruby_event_store/outbox/sidekiq_producer.rb +27 -0
- data/lib/ruby_event_store/outbox/sidekiq_scheduler.rb +9 -16
- data/lib/ruby_event_store/outbox/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b73edc767b3c0caa9ff76cd06a58468e18aa2556f25a7c170bd9f0da6bdce9a
|
4
|
+
data.tar.gz: b96f01c515c3975694b7ba54ab9b8057bb506534d22c313823488f0150b98ce3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9c3e4f4d5733cb1afbea5ffa9ae91af3c1e4ef17f6d371a9dff483e95a4034f57c0bbe1166a87b5e44f562773f683d5442eaa60b0a704439d974c0718a74a49
|
7
|
+
data.tar.gz: 5a1e56fd33a9f296246ed9c429dc9abf35e7fed714c9a2b30cb6aaf926babf505a09c8a093a3aba77076aa6f6727f3568d4677035bec47289181811878534a0a
|
@@ -11,5 +11,13 @@ class CreateEventStoreOutbox < ActiveRecord::Migration<%= migration_version %>
|
|
11
11
|
end
|
12
12
|
add_index :event_store_outbox, [:format, :enqueued_at, :split_key], name: "index_event_store_outbox_for_pool"
|
13
13
|
add_index :event_store_outbox, [:created_at, :enqueued_at], name: "index_event_store_outbox_for_clear"
|
14
|
+
|
15
|
+
create_table(:event_store_outbox_locks, force: false) do |t|
|
16
|
+
t.string :format, null: false
|
17
|
+
t.string :split_key, null: false
|
18
|
+
t.datetime :locked_at, null: true
|
19
|
+
t.string :locked_by, null: true, limit: 36
|
20
|
+
end
|
21
|
+
add_index :event_store_outbox_locks, [:format, :split_key], name: "index_event_store_outbox_locks_for_locking", unique: true
|
14
22
|
end
|
15
23
|
end
|
@@ -59,9 +59,8 @@ module RubyEventStore
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def build_consumer(options)
|
62
|
-
|
63
|
-
|
64
|
-
# ActiveSupport::LogSubscriber.colorize_logging = false
|
62
|
+
consumer_uuid = SecureRandom.uuid
|
63
|
+
logger = Logger.new(STDOUT, level: options.log_level, progname: "RES-Outbox #{consumer_uuid}")
|
65
64
|
consumer_configuration = Consumer::Configuration.new(
|
66
65
|
split_keys: options.split_keys,
|
67
66
|
message_format: options.message_format,
|
@@ -71,6 +70,7 @@ module RubyEventStore
|
|
71
70
|
)
|
72
71
|
metrics = Metrics.from_url(options.metrics_url)
|
73
72
|
outbox_consumer = RubyEventStore::Outbox::Consumer.new(
|
73
|
+
consumer_uuid,
|
74
74
|
options,
|
75
75
|
logger: logger,
|
76
76
|
metrics: metrics,
|
@@ -3,11 +3,14 @@ require "redis"
|
|
3
3
|
require "active_record"
|
4
4
|
require "ruby_event_store/outbox/record"
|
5
5
|
require "ruby_event_store/outbox/sidekiq5_format"
|
6
|
+
require "ruby_event_store/outbox/sidekiq_processor"
|
7
|
+
require "ruby_event_store/outbox/fetch_specification"
|
6
8
|
|
7
9
|
module RubyEventStore
|
8
10
|
module Outbox
|
9
11
|
class Consumer
|
10
12
|
SLEEP_TIME_WHEN_NOTHING_TO_DO = 0.1
|
13
|
+
MAXIMUM_BATCH_FETCHES_IN_ONE_LOCK = 10
|
11
14
|
|
12
15
|
class Configuration
|
13
16
|
def initialize(
|
@@ -38,25 +41,26 @@ module RubyEventStore
|
|
38
41
|
attr_reader :split_keys, :message_format, :batch_size, :database_url, :redis_url
|
39
42
|
end
|
40
43
|
|
41
|
-
def initialize(configuration, clock: Time, logger:, metrics:)
|
44
|
+
def initialize(consumer_uuid, configuration, clock: Time, logger:, metrics:)
|
42
45
|
@split_keys = configuration.split_keys
|
43
46
|
@clock = clock
|
44
|
-
@redis = Redis.new(url: configuration.redis_url)
|
45
47
|
@logger = logger
|
46
48
|
@metrics = metrics
|
47
49
|
@batch_size = configuration.batch_size
|
50
|
+
@consumer_uuid = consumer_uuid
|
48
51
|
ActiveRecord::Base.establish_connection(configuration.database_url) unless ActiveRecord::Base.connected?
|
49
|
-
ActiveRecord::Base.connection.
|
52
|
+
if ActiveRecord::Base.connection.adapter_name == "Mysql2"
|
53
|
+
ActiveRecord::Base.connection.execute("SET SESSION innodb_lock_wait_timeout = 1;")
|
54
|
+
end
|
50
55
|
|
51
56
|
raise "Unknown format" if configuration.message_format != SIDEKIQ5_FORMAT
|
52
|
-
@
|
57
|
+
@processor = SidekiqProcessor.new(Redis.new(url: configuration.redis_url))
|
53
58
|
|
54
59
|
@gracefully_shutting_down = false
|
55
60
|
prepare_traps
|
56
61
|
end
|
57
62
|
|
58
63
|
def init
|
59
|
-
@redis.sadd("queues", split_keys)
|
60
64
|
logger.info("Initiated RubyEventStore::Outbox v#{VERSION}")
|
61
65
|
logger.info("Handling split keys: #{split_keys ? split_keys.join(", ") : "(all of them)"}")
|
62
66
|
end
|
@@ -73,51 +77,129 @@ module RubyEventStore
|
|
73
77
|
end
|
74
78
|
|
75
79
|
def one_loop
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
remaining_split_keys = @split_keys.dup
|
81
|
+
|
82
|
+
was_something_changed = false
|
83
|
+
while (split_key = remaining_split_keys.shift)
|
84
|
+
was_something_changed |= handle_split(FetchSpecification.new(processor.message_format, split_key))
|
85
|
+
end
|
86
|
+
was_something_changed
|
87
|
+
end
|
88
|
+
|
89
|
+
def handle_split(fetch_specification)
|
90
|
+
obtained_lock = obtain_lock_for_process(fetch_specification)
|
91
|
+
return false unless obtained_lock
|
92
|
+
|
93
|
+
something_processed = false
|
94
|
+
|
95
|
+
MAXIMUM_BATCH_FETCHES_IN_ONE_LOCK.times do
|
96
|
+
batch = retrieve_batch(fetch_specification)
|
97
|
+
if batch.empty?
|
98
|
+
break
|
83
99
|
end
|
84
100
|
|
85
|
-
now = @clock.now.utc
|
86
101
|
failed_record_ids = []
|
87
|
-
|
102
|
+
updated_record_ids = []
|
103
|
+
batch.each do |record|
|
88
104
|
begin
|
89
|
-
|
105
|
+
now = @clock.now.utc
|
106
|
+
processor.process(record, now)
|
107
|
+
|
108
|
+
record.update_column(:enqueued_at, now)
|
109
|
+
something_processed |= true
|
110
|
+
updated_record_ids << record.id
|
90
111
|
rescue => e
|
91
112
|
failed_record_ids << record.id
|
92
113
|
e.full_message.split($/).each {|line| logger.error(line) }
|
93
114
|
end
|
94
115
|
end
|
95
116
|
|
96
|
-
|
97
|
-
|
98
|
-
|
117
|
+
metrics.write_point_queue(
|
118
|
+
enqueued: updated_record_ids.size,
|
119
|
+
failed: failed_record_ids.size,
|
120
|
+
format: fetch_specification.message_format,
|
121
|
+
split_key: fetch_specification.split_key,
|
122
|
+
remaining: get_remaining_count(fetch_specification)
|
123
|
+
)
|
124
|
+
|
125
|
+
logger.info "Sent #{updated_record_ids.size} messages from outbox table"
|
99
126
|
|
100
|
-
|
101
|
-
|
127
|
+
obtained_lock = refresh_lock_for_process(obtained_lock)
|
128
|
+
break unless obtained_lock
|
102
129
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
130
|
+
|
131
|
+
metrics.write_point_queue(
|
132
|
+
format: fetch_specification.message_format,
|
133
|
+
split_key: fetch_specification.split_key,
|
134
|
+
remaining: get_remaining_count(fetch_specification)
|
135
|
+
) unless something_processed
|
136
|
+
|
137
|
+
release_lock_for_process(fetch_specification)
|
138
|
+
|
139
|
+
processor.after_batch
|
140
|
+
|
141
|
+
something_processed
|
111
142
|
end
|
112
143
|
|
113
144
|
private
|
114
|
-
attr_reader :split_keys, :logger, :
|
145
|
+
attr_reader :split_keys, :logger, :batch_size, :metrics, :processor, :consumer_uuid
|
146
|
+
|
147
|
+
def obtain_lock_for_process(fetch_specification)
|
148
|
+
result = Lock.obtain(fetch_specification, consumer_uuid, clock: @clock)
|
149
|
+
case result
|
150
|
+
when :deadlocked
|
151
|
+
logger.warn "Obtaining lock for split_key '#{fetch_specification.split_key}' failed (deadlock)"
|
152
|
+
metrics.write_operation_result("obtain", "deadlocked")
|
153
|
+
return false
|
154
|
+
when :lock_timeout
|
155
|
+
logger.warn "Obtaining lock for split_key '#{fetch_specification.split_key}' failed (lock timeout)"
|
156
|
+
metrics.write_operation_result("obtain", "lock_timeout")
|
157
|
+
return false
|
158
|
+
when :taken
|
159
|
+
logger.debug "Obtaining lock for split_key '#{fetch_specification.split_key}' unsuccessful (taken)"
|
160
|
+
metrics.write_operation_result("obtain", "taken")
|
161
|
+
return false
|
162
|
+
else
|
163
|
+
return result
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def release_lock_for_process(fetch_specification)
|
168
|
+
result = Lock.release(fetch_specification, consumer_uuid)
|
169
|
+
case result
|
170
|
+
when :ok
|
171
|
+
when :deadlocked
|
172
|
+
logger.warn "Releasing lock for split_key '#{fetch_specification.split_key}' failed (deadlock)"
|
173
|
+
metrics.write_operation_result("release", "deadlocked")
|
174
|
+
when :lock_timeout
|
175
|
+
logger.warn "Releasing lock for split_key '#{fetch_specification.split_key}' failed (lock timeout)"
|
176
|
+
metrics.write_operation_result("release", "lock_timeout")
|
177
|
+
when :not_taken_by_this_process
|
178
|
+
logger.debug "Releasing lock for split_key '#{fetch_specification.split_key}' failed (not taken by this process)"
|
179
|
+
metrics.write_operation_result("release", "not_taken_by_this_process")
|
180
|
+
else
|
181
|
+
raise "Unexpected result #{result}"
|
182
|
+
end
|
183
|
+
end
|
115
184
|
|
116
|
-
def
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
185
|
+
def refresh_lock_for_process(lock)
|
186
|
+
result = lock.refresh(clock: @clock)
|
187
|
+
case result
|
188
|
+
when :deadlocked
|
189
|
+
logger.warn "Refreshing lock for split_key '#{lock.split_key}' failed (deadlock)"
|
190
|
+
metrics.write_operation_result("refresh", "deadlocked")
|
191
|
+
return false
|
192
|
+
when :lock_timeout
|
193
|
+
logger.warn "Refreshing lock for split_key '#{lock.split_key}' failed (lock timeout)"
|
194
|
+
metrics.write_operation_result("refresh", "lock_timeout")
|
195
|
+
return false
|
196
|
+
when :stolen
|
197
|
+
logger.debug "Refreshing lock for split_key '#{lock.split_key}' unsuccessful (stolen)"
|
198
|
+
metrics.write_operation_result("refresh", "stolen")
|
199
|
+
return false
|
200
|
+
else
|
201
|
+
return result
|
202
|
+
end
|
121
203
|
end
|
122
204
|
|
123
205
|
def prepare_traps
|
@@ -132,6 +214,14 @@ module RubyEventStore
|
|
132
214
|
def initiate_graceful_shutdown
|
133
215
|
@gracefully_shutting_down = true
|
134
216
|
end
|
217
|
+
|
218
|
+
def retrieve_batch(fetch_specification)
|
219
|
+
Record.remaining_for(fetch_specification).order("id ASC").limit(batch_size).to_a
|
220
|
+
end
|
221
|
+
|
222
|
+
def get_remaining_count(fetch_specification)
|
223
|
+
Record.remaining_for(fetch_specification).count
|
224
|
+
end
|
135
225
|
end
|
136
226
|
end
|
137
227
|
end
|
@@ -1,13 +1,12 @@
|
|
1
|
-
require "ruby_event_store/outbox/metrics/null"
|
2
|
-
require "ruby_event_store/outbox/metrics/influx"
|
3
|
-
|
4
1
|
module RubyEventStore
|
5
2
|
module Outbox
|
6
3
|
module Metrics
|
7
4
|
def self.from_url(metrics_url)
|
8
5
|
if metrics_url.nil?
|
6
|
+
require "ruby_event_store/outbox/metrics/null"
|
9
7
|
Null.new
|
10
8
|
else
|
9
|
+
require "ruby_event_store/outbox/metrics/influx"
|
11
10
|
Influx.new(metrics_url)
|
12
11
|
end
|
13
12
|
end
|
@@ -12,26 +12,40 @@ module RubyEventStore
|
|
12
12
|
async: true,
|
13
13
|
time_precision: 'ns',
|
14
14
|
}
|
15
|
-
options[:username] = params
|
16
|
-
options[:password] = params
|
15
|
+
options[:username] = params.fetch("username").first if params.key?("username")
|
16
|
+
options[:password] = params.fetch("password").first if params.key?("password")
|
17
17
|
@influxdb_client = InfluxDB::Client.new(**options)
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def write_operation_result(operation, result)
|
21
|
+
write_point("ruby_event_store.outbox.lock", {
|
22
|
+
values: {
|
23
|
+
value: 1,
|
24
|
+
},
|
25
|
+
tags: {
|
26
|
+
operation: operation,
|
27
|
+
result: result,
|
28
|
+
}
|
29
|
+
})
|
30
|
+
end
|
31
|
+
|
32
|
+
def write_point_queue(enqueued: 0, failed: 0, remaining: 0, format: nil, split_key: nil)
|
21
33
|
write_point("ruby_event_store.outbox.queue", {
|
22
34
|
values: {
|
23
35
|
enqueued: enqueued,
|
24
36
|
failed: failed,
|
37
|
+
remaining: remaining,
|
25
38
|
},
|
26
39
|
tags: {
|
27
|
-
|
40
|
+
format: format,
|
41
|
+
split_key: split_key,
|
28
42
|
}
|
29
43
|
})
|
30
44
|
end
|
31
45
|
|
32
46
|
def write_point(series, data)
|
33
|
-
data[:timestamp]
|
34
|
-
|
47
|
+
data[:timestamp] = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
|
48
|
+
influxdb_client.write_point(series, data)
|
35
49
|
end
|
36
50
|
|
37
51
|
attr_reader :influxdb_client
|
@@ -8,9 +8,97 @@ module RubyEventStore
|
|
8
8
|
self.primary_key = :id
|
9
9
|
self.table_name = 'event_store_outbox'
|
10
10
|
|
11
|
+
def self.remaining_for(fetch_specification)
|
12
|
+
where(format: fetch_specification.message_format, split_key: fetch_specification.split_key, enqueued_at: nil)
|
13
|
+
end
|
14
|
+
|
11
15
|
def hash_payload
|
12
16
|
JSON.parse(payload).deep_symbolize_keys
|
13
17
|
end
|
18
|
+
|
19
|
+
def enqueued?
|
20
|
+
!enqueued_at.nil?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Lock < ::ActiveRecord::Base
|
25
|
+
self.primary_key = :split_key
|
26
|
+
self.table_name = 'event_store_outbox_locks'
|
27
|
+
|
28
|
+
def self.obtain(fetch_specification, process_uuid, clock:)
|
29
|
+
l = nil
|
30
|
+
transaction do
|
31
|
+
l = get_lock_record(fetch_specification)
|
32
|
+
|
33
|
+
return :taken if l.recently_locked?
|
34
|
+
|
35
|
+
l.update!(
|
36
|
+
locked_by: process_uuid,
|
37
|
+
locked_at: clock.now,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
l
|
41
|
+
rescue ActiveRecord::Deadlocked
|
42
|
+
:deadlocked
|
43
|
+
rescue ActiveRecord::LockWaitTimeout
|
44
|
+
:lock_timeout
|
45
|
+
end
|
46
|
+
|
47
|
+
def refresh(clock:)
|
48
|
+
transaction do
|
49
|
+
current_process_uuid = locked_by
|
50
|
+
lock!
|
51
|
+
if locked_by == current_process_uuid
|
52
|
+
update!(locked_at: clock.now)
|
53
|
+
return self
|
54
|
+
else
|
55
|
+
return :stolen
|
56
|
+
end
|
57
|
+
end
|
58
|
+
rescue ActiveRecord::Deadlocked
|
59
|
+
:deadlocked
|
60
|
+
rescue ActiveRecord::LockWaitTimeout
|
61
|
+
:lock_timeout
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.release(fetch_specification, process_uuid)
|
65
|
+
transaction do
|
66
|
+
l = get_lock_record(fetch_specification)
|
67
|
+
return :not_taken_by_this_process if !l.locked_by?(process_uuid)
|
68
|
+
|
69
|
+
l.update!(locked_by: nil, locked_at: nil)
|
70
|
+
end
|
71
|
+
:ok
|
72
|
+
rescue ActiveRecord::Deadlocked
|
73
|
+
:deadlocked
|
74
|
+
rescue ActiveRecord::LockWaitTimeout
|
75
|
+
:lock_timeout
|
76
|
+
end
|
77
|
+
|
78
|
+
def locked_by?(process_uuid)
|
79
|
+
locked_by.eql?(process_uuid)
|
80
|
+
end
|
81
|
+
|
82
|
+
def recently_locked?
|
83
|
+
locked_by && locked_at > 10.minutes.ago
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def self.lock_for_split_key(fetch_specification)
|
88
|
+
lock.find_by(format: fetch_specification.message_format, split_key: fetch_specification.split_key)
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.get_lock_record(fetch_specification)
|
92
|
+
l = lock_for_split_key(fetch_specification)
|
93
|
+
if l.nil?
|
94
|
+
begin
|
95
|
+
l = create!(format: fetch_specification.message_format, split_key: fetch_specification.split_key)
|
96
|
+
rescue ActiveRecord::RecordNotUnique
|
97
|
+
l = lock_for_split_key(fetch_specification)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
l
|
101
|
+
end
|
14
102
|
end
|
15
103
|
end
|
16
104
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ruby_event_store/outbox/sidekiq5_format"
|
4
|
+
|
5
|
+
module RubyEventStore
|
6
|
+
module Outbox
|
7
|
+
class SidekiqProcessor
|
8
|
+
InvalidPayload = Class.new(StandardError)
|
9
|
+
|
10
|
+
def initialize(redis)
|
11
|
+
@redis = redis
|
12
|
+
@recently_used_queues = Set.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def process(record, now)
|
16
|
+
parsed_record = JSON.parse(record.payload)
|
17
|
+
|
18
|
+
queue = parsed_record["queue"]
|
19
|
+
raise InvalidPayload.new("Missing queue") if queue.nil? || queue.empty?
|
20
|
+
payload = JSON.generate(parsed_record.merge({
|
21
|
+
"enqueued_at" => now.to_f,
|
22
|
+
}))
|
23
|
+
|
24
|
+
redis.lpush("queue:#{queue}", payload)
|
25
|
+
|
26
|
+
@recently_used_queues << queue
|
27
|
+
end
|
28
|
+
|
29
|
+
def after_batch
|
30
|
+
if !@recently_used_queues.empty?
|
31
|
+
redis.sadd("queues", @recently_used_queues.to_a)
|
32
|
+
@recently_used_queues.clear
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def message_format
|
37
|
+
SIDEKIQ5_FORMAT
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
attr_reader :redis
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sidekiq'
|
4
|
+
require "ruby_event_store/outbox/sidekiq5_format"
|
5
|
+
|
6
|
+
module RubyEventStore
|
7
|
+
module Outbox
|
8
|
+
class SidekiqProducer
|
9
|
+
def call(klass, args)
|
10
|
+
sidekiq_client = Sidekiq::Client.new(Sidekiq.redis_pool)
|
11
|
+
item = {
|
12
|
+
'class' => klass,
|
13
|
+
'args' => args,
|
14
|
+
}
|
15
|
+
normalized_item = sidekiq_client.__send__(:normalize_item, item)
|
16
|
+
payload = sidekiq_client.__send__(:process_single, normalized_item.fetch('class'), normalized_item)
|
17
|
+
if payload
|
18
|
+
Record.create!(
|
19
|
+
format: SIDEKIQ5_FORMAT,
|
20
|
+
split_key: payload.fetch('queue'),
|
21
|
+
payload: payload.to_json
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,31 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require "ruby_event_store/outbox/sidekiq5_format"
|
3
|
+
require "ruby_event_store/outbox/sidekiq_producer"
|
5
4
|
|
6
5
|
module RubyEventStore
|
7
6
|
module Outbox
|
8
7
|
class SidekiqScheduler
|
8
|
+
def initialize
|
9
|
+
@sidekiq_producer = SidekiqProducer.new
|
10
|
+
end
|
11
|
+
|
9
12
|
def call(klass, serialized_event)
|
10
|
-
|
11
|
-
item = {
|
12
|
-
'class' => klass,
|
13
|
-
'args' => [serialized_event.to_h],
|
14
|
-
}
|
15
|
-
normalized_item = sidekiq_client.__send__(:normalize_item, item)
|
16
|
-
payload = sidekiq_client.__send__(:process_single, normalized_item.fetch('class'), normalized_item)
|
17
|
-
if payload
|
18
|
-
Record.create!(
|
19
|
-
format: SIDEKIQ5_FORMAT,
|
20
|
-
split_key: payload.fetch('queue'),
|
21
|
-
payload: payload.to_json
|
22
|
-
)
|
23
|
-
end
|
13
|
+
sidekiq_producer.call(klass, [serialized_event.to_h])
|
24
14
|
end
|
25
15
|
|
26
16
|
def verify(subscriber)
|
27
17
|
Class === subscriber && subscriber.respond_to?(:through_outbox?) && subscriber.through_outbox?
|
28
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
attr_reader :sidekiq_producer
|
29
22
|
end
|
30
23
|
end
|
31
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_event_store-outbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arkency
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby_event_store
|
@@ -53,12 +53,16 @@ files:
|
|
53
53
|
- lib/ruby_event_store/outbox.rb
|
54
54
|
- lib/ruby_event_store/outbox/cli.rb
|
55
55
|
- lib/ruby_event_store/outbox/consumer.rb
|
56
|
+
- lib/ruby_event_store/outbox/consumer_process.rb
|
57
|
+
- lib/ruby_event_store/outbox/fetch_specification.rb
|
56
58
|
- lib/ruby_event_store/outbox/metrics.rb
|
57
59
|
- lib/ruby_event_store/outbox/metrics/influx.rb
|
58
60
|
- lib/ruby_event_store/outbox/metrics/null.rb
|
59
61
|
- lib/ruby_event_store/outbox/record.rb
|
60
62
|
- lib/ruby_event_store/outbox/sidekiq5_format.rb
|
61
63
|
- lib/ruby_event_store/outbox/sidekiq_message_handler.rb
|
64
|
+
- lib/ruby_event_store/outbox/sidekiq_processor.rb
|
65
|
+
- lib/ruby_event_store/outbox/sidekiq_producer.rb
|
62
66
|
- lib/ruby_event_store/outbox/sidekiq_scheduler.rb
|
63
67
|
- lib/ruby_event_store/outbox/version.rb
|
64
68
|
homepage: https://railseventstore.org
|