ruby_event_store-outbox 0.0.16 → 0.0.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -2
- data/lib/ruby_event_store/outbox/cli.rb +29 -13
- data/lib/ruby_event_store/outbox/consumer.rb +15 -12
- data/lib/ruby_event_store/outbox/metrics/influx.rb +0 -3
- data/lib/ruby_event_store/outbox/metrics.rb +2 -2
- data/lib/ruby_event_store/outbox/sidekiq_processor.rb +1 -1
- data/lib/ruby_event_store/outbox/sidekiq_producer.rb +1 -1
- data/lib/ruby_event_store/outbox/sidekiq_scheduler.rb +1 -1
- data/lib/ruby_event_store/outbox/version.rb +1 -1
- metadata +8 -11
- data/lib/ruby_event_store/outbox/consumer_process.rb +0 -6
- data/lib/ruby_event_store/outbox/sidekiq_message_handler.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dbabda53c709b7e11850772272b736226ed33e441392e9f7a1b7b5e3ead47b7
|
4
|
+
data.tar.gz: 02eec2972f701e1ecc09bd65c38cecafef53d4dc45f95f69a869457289a1edcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aec65f023d21c3a86204b31b22ae1b21157f46c39869a22e522efe7b13e320cd3d4f75ef139c6e421d40b203a3d33bcb368cf16cb98552ff803380a36469290a
|
7
|
+
data.tar.gz: 6fa822fb40b763717f31297944423bcb708400ba3bfad9852cde4edc99f79308ad3bb837ffc593d2cae6942961735a6d5c6c9bf25088bafbaea9b48f2d278842
|
data/README.md
CHANGED
@@ -14,6 +14,12 @@ Add to your gemfile in application:
|
|
14
14
|
gem "ruby_event_store-outbox"
|
15
15
|
```
|
16
16
|
|
17
|
+
Generate and execute the migration adding necessary tables. If it's needed, change the type of the `payload` column to `mediumbinary` or `longbinary`.
|
18
|
+
|
19
|
+
```
|
20
|
+
bin/rails generate ruby_event_store:outbox:migration
|
21
|
+
```
|
22
|
+
|
17
23
|
In your event store configuration, as a dispatcher use `RubyEventStore::ImmediateAsyncDispatcher` with `RubyEventStore::Outbox::SidekiqScheduler`, for example:
|
18
24
|
|
19
25
|
```ruby
|
@@ -38,14 +44,18 @@ end
|
|
38
44
|
Run following process in any way you prefer:
|
39
45
|
|
40
46
|
```
|
41
|
-
res_outbox
|
47
|
+
res_outbox \
|
48
|
+
--database-url="mysql2://root@0.0.0.0:3306/my_database" \
|
49
|
+
--redis-url="redis://localhost:6379/0" \
|
50
|
+
--log-level=info \
|
51
|
+
--split-keys=sidekiq_queue1,sidekiq_queue2
|
42
52
|
```
|
43
53
|
|
44
54
|
It is possible to run as many instances as you prefer, but it does not make sense to run more instances than there are different split keys (sidekiq queues), as one process is operating at one moment only one split key.
|
45
55
|
|
46
56
|
### Metrics
|
47
57
|
|
48
|
-
It is possible for the outbox process to send metrics to InfluxDB. In order to do that, specify a `--metrics-url` parameter, for example:
|
58
|
+
It is possible for the outbox process to send metrics to InfluxDB (this requires influxdb gem in version at least 0.8.1). In order to do that, specify a `--metrics-url` parameter, for example:
|
49
59
|
|
50
60
|
```
|
51
61
|
res_outbox --database-url="mysql2://root@0.0.0.0:3306/my_database" \
|
@@ -59,3 +69,11 @@ res_outbox --database-url="mysql2://root@0.0.0.0:3306/my_database" \
|
|
59
69
|
## Contributing
|
60
70
|
|
61
71
|
Bug reports and pull requests are welcome on GitHub at https://github.com/RailsEventStore/rails_event_store.
|
72
|
+
|
73
|
+
## Releasing
|
74
|
+
|
75
|
+
1. Bump version
|
76
|
+
2. `make build`
|
77
|
+
3. `make push`
|
78
|
+
4. `make docker-build`
|
79
|
+
5. `make docker-push`
|
@@ -1,51 +1,66 @@
|
|
1
1
|
require "optparse"
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
require_relative "version"
|
3
|
+
require_relative "consumer"
|
4
|
+
require_relative "metrics"
|
5
5
|
|
6
6
|
module RubyEventStore
|
7
7
|
module Outbox
|
8
8
|
class CLI
|
9
|
-
|
9
|
+
DEFAULTS = {
|
10
|
+
database_url: nil,
|
11
|
+
redis_url: nil,
|
12
|
+
log_level: :warn,
|
13
|
+
split_keys: nil,
|
14
|
+
message_format: 'sidekiq5',
|
15
|
+
batch_size: 100,
|
16
|
+
metrics_url: nil,
|
17
|
+
cleanup_strategy: :none,
|
18
|
+
sleep_on_empty: 0.5
|
19
|
+
}
|
20
|
+
Options = Struct.new(*DEFAULTS.keys)
|
10
21
|
|
11
22
|
class Parser
|
12
23
|
def self.parse(argv)
|
13
|
-
options = Options.new(
|
24
|
+
options = Options.new(*DEFAULTS.values)
|
14
25
|
OptionParser.new do |option_parser|
|
15
26
|
option_parser.banner = "Usage: res_outbox [options]"
|
16
27
|
|
17
|
-
option_parser.on("--database-url
|
28
|
+
option_parser.on("--database-url=DATABASE_URL", "Database where outbox table is stored") do |database_url|
|
18
29
|
options.database_url = database_url
|
19
30
|
end
|
20
31
|
|
21
|
-
option_parser.on("--redis-url
|
32
|
+
option_parser.on("--redis-url=REDIS_URL", "URL to redis database") do |redis_url|
|
22
33
|
options.redis_url = redis_url
|
23
34
|
end
|
24
35
|
|
25
|
-
option_parser.on("--log-level
|
36
|
+
option_parser.on("--log-level=LOG_LEVEL", [:fatal, :error, :warn, :info, :debug], "Logging level, one of: fatal, error, warn, info, debug. Default: warn") do |log_level|
|
26
37
|
options.log_level = log_level.to_sym
|
27
38
|
end
|
28
39
|
|
29
|
-
option_parser.on("--message-format
|
40
|
+
option_parser.on("--message-format=FORMAT", ["sidekiq5"], "Message format, supported: sidekiq5. Default: sidekiq5") do |message_format|
|
30
41
|
options.message_format = message_format
|
31
42
|
end
|
32
43
|
|
33
|
-
option_parser.on("--split-keys=
|
44
|
+
option_parser.on("--split-keys=SPLIT_KEYS", Array, "Split keys which should be handled, all if not specified") do |split_keys|
|
34
45
|
options.split_keys = split_keys if !split_keys.empty?
|
35
46
|
end
|
36
47
|
|
37
|
-
option_parser.on("--batch-size
|
48
|
+
option_parser.on("--batch-size=BATCH_SIZE", Integer, "Amount of records fetched in one fetch. Bigger value means more duplicated messages when network problems occur. Default: 100") do |batch_size|
|
38
49
|
options.batch_size = batch_size
|
39
50
|
end
|
40
51
|
|
41
|
-
option_parser.on("--metrics-url
|
52
|
+
option_parser.on("--metrics-url=METRICS_URL", "URI to metrics collector, optional") do |metrics_url|
|
42
53
|
options.metrics_url = metrics_url
|
43
54
|
end
|
44
55
|
|
45
|
-
option_parser.on("--cleanup
|
56
|
+
option_parser.on("--cleanup=STRATEGY", "A strategy for cleaning old records. One of: none or iso8601 duration format how old enqueued records should be removed. Default: none") do |cleanup_strategy|
|
46
57
|
options.cleanup_strategy = cleanup_strategy
|
47
58
|
end
|
48
59
|
|
60
|
+
option_parser.on("--sleep-on-empty=SLEEP_TIME", Float, "How long to sleep before next check when there was nothing to do. Default: 0.5") do |sleep_on_empty|
|
61
|
+
options.sleep_on_empty = sleep_on_empty
|
62
|
+
end
|
63
|
+
|
49
64
|
option_parser.on_tail("--version", "Show version") do
|
50
65
|
puts VERSION
|
51
66
|
exit
|
@@ -72,6 +87,7 @@ module RubyEventStore
|
|
72
87
|
database_url: options.database_url,
|
73
88
|
redis_url: options.redis_url,
|
74
89
|
cleanup: options.cleanup_strategy,
|
90
|
+
sleep_on_empty: options.sleep_on_empty,
|
75
91
|
)
|
76
92
|
metrics = Metrics.from_url(options.metrics_url)
|
77
93
|
outbox_consumer = RubyEventStore::Outbox::Consumer.new(
|
@@ -1,17 +1,16 @@
|
|
1
1
|
require "logger"
|
2
2
|
require "redis"
|
3
3
|
require "active_record"
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
require_relative "repository"
|
5
|
+
require_relative "sidekiq5_format"
|
6
|
+
require_relative "sidekiq_processor"
|
7
|
+
require_relative "fetch_specification"
|
8
|
+
require_relative "cleanup_strategies/none"
|
9
|
+
require_relative "cleanup_strategies/clean_old_enqueued"
|
10
10
|
|
11
11
|
module RubyEventStore
|
12
12
|
module Outbox
|
13
13
|
class Consumer
|
14
|
-
SLEEP_TIME_WHEN_NOTHING_TO_DO = 0.5
|
15
14
|
MAXIMUM_BATCH_FETCHES_IN_ONE_LOCK = 10
|
16
15
|
|
17
16
|
class Configuration
|
@@ -21,7 +20,8 @@ module RubyEventStore
|
|
21
20
|
batch_size:,
|
22
21
|
database_url:,
|
23
22
|
redis_url:,
|
24
|
-
cleanup
|
23
|
+
cleanup:,
|
24
|
+
sleep_on_empty:
|
25
25
|
)
|
26
26
|
@split_keys = split_keys
|
27
27
|
@message_format = message_format
|
@@ -29,6 +29,7 @@ module RubyEventStore
|
|
29
29
|
@database_url = database_url
|
30
30
|
@redis_url = redis_url
|
31
31
|
@cleanup = cleanup
|
32
|
+
@sleep_on_empty = sleep_on_empty
|
32
33
|
freeze
|
33
34
|
end
|
34
35
|
|
@@ -39,11 +40,12 @@ module RubyEventStore
|
|
39
40
|
batch_size: overriden_options.fetch(:batch_size, batch_size),
|
40
41
|
database_url: overriden_options.fetch(:database_url, database_url),
|
41
42
|
redis_url: overriden_options.fetch(:redis_url, redis_url),
|
42
|
-
cleanup: overriden_options.fetch(:cleanup, cleanup)
|
43
|
+
cleanup: overriden_options.fetch(:cleanup, cleanup),
|
44
|
+
sleep_on_empty: overriden_options.fetch(:sleep_on_empty, sleep_on_empty)
|
43
45
|
)
|
44
46
|
end
|
45
47
|
|
46
|
-
attr_reader :split_keys, :message_format, :batch_size, :database_url, :redis_url, :cleanup
|
48
|
+
attr_reader :split_keys, :message_format, :batch_size, :database_url, :redis_url, :cleanup, :sleep_on_empty
|
47
49
|
end
|
48
50
|
|
49
51
|
def initialize(consumer_uuid, configuration, clock: Time, logger:, metrics:)
|
@@ -52,6 +54,7 @@ module RubyEventStore
|
|
52
54
|
@logger = logger
|
53
55
|
@metrics = metrics
|
54
56
|
@batch_size = configuration.batch_size
|
57
|
+
@sleep_on_empty = configuration.sleep_on_empty
|
55
58
|
@consumer_uuid = consumer_uuid
|
56
59
|
|
57
60
|
raise "Unknown format" if configuration.message_format != SIDEKIQ5_FORMAT
|
@@ -79,7 +82,7 @@ module RubyEventStore
|
|
79
82
|
was_something_changed = one_loop
|
80
83
|
if !was_something_changed
|
81
84
|
STDOUT.flush
|
82
|
-
sleep
|
85
|
+
sleep sleep_on_empty
|
83
86
|
end
|
84
87
|
end
|
85
88
|
logger.info "Gracefully shutting down"
|
@@ -153,7 +156,7 @@ module RubyEventStore
|
|
153
156
|
end
|
154
157
|
|
155
158
|
private
|
156
|
-
attr_reader :split_keys, :logger, :batch_size, :metrics, :processor, :consumer_uuid, :repository, :cleanup_strategy
|
159
|
+
attr_reader :split_keys, :logger, :batch_size, :metrics, :processor, :consumer_uuid, :repository, :cleanup_strategy, :sleep_on_empty
|
157
160
|
|
158
161
|
def obtain_lock_for_process(fetch_specification)
|
159
162
|
result = repository.obtain_lock_for_process(fetch_specification, consumer_uuid, clock: @clock)
|
@@ -6,14 +6,11 @@ module RubyEventStore
|
|
6
6
|
class Influx
|
7
7
|
def initialize(url)
|
8
8
|
uri = URI.parse(url)
|
9
|
-
params = CGI.parse(uri.query || "")
|
10
9
|
options = {
|
11
10
|
url: url,
|
12
11
|
async: true,
|
13
12
|
time_precision: 'ns',
|
14
13
|
}
|
15
|
-
options[:username] = params.fetch("username").first if params.key?("username")
|
16
|
-
options[:password] = params.fetch("password").first if params.key?("password")
|
17
14
|
@influxdb_client = InfluxDB::Client.new(**options)
|
18
15
|
end
|
19
16
|
|
@@ -3,10 +3,10 @@ module RubyEventStore
|
|
3
3
|
module Metrics
|
4
4
|
def self.from_url(metrics_url)
|
5
5
|
if metrics_url.nil?
|
6
|
-
|
6
|
+
require_relative "metrics/null"
|
7
7
|
Null.new
|
8
8
|
else
|
9
|
-
|
9
|
+
require_relative "metrics/influx"
|
10
10
|
Influx.new(metrics_url)
|
11
11
|
end
|
12
12
|
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.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arkency
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby_event_store
|
@@ -39,12 +39,12 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '5.2'
|
41
41
|
description:
|
42
|
-
email:
|
43
|
-
- dev@arkency.com
|
42
|
+
email: dev@arkency.com
|
44
43
|
executables:
|
45
44
|
- res_outbox
|
46
45
|
extensions: []
|
47
|
-
extra_rdoc_files:
|
46
|
+
extra_rdoc_files:
|
47
|
+
- README.md
|
48
48
|
files:
|
49
49
|
- README.md
|
50
50
|
- bin/res_outbox
|
@@ -55,14 +55,12 @@ files:
|
|
55
55
|
- lib/ruby_event_store/outbox/cleanup_strategies/none.rb
|
56
56
|
- lib/ruby_event_store/outbox/cli.rb
|
57
57
|
- lib/ruby_event_store/outbox/consumer.rb
|
58
|
-
- lib/ruby_event_store/outbox/consumer_process.rb
|
59
58
|
- lib/ruby_event_store/outbox/fetch_specification.rb
|
60
59
|
- lib/ruby_event_store/outbox/metrics.rb
|
61
60
|
- lib/ruby_event_store/outbox/metrics/influx.rb
|
62
61
|
- lib/ruby_event_store/outbox/metrics/null.rb
|
63
62
|
- lib/ruby_event_store/outbox/repository.rb
|
64
63
|
- lib/ruby_event_store/outbox/sidekiq5_format.rb
|
65
|
-
- lib/ruby_event_store/outbox/sidekiq_message_handler.rb
|
66
64
|
- lib/ruby_event_store/outbox/sidekiq_processor.rb
|
67
65
|
- lib/ruby_event_store/outbox/sidekiq_producer.rb
|
68
66
|
- lib/ruby_event_store/outbox/sidekiq_scheduler.rb
|
@@ -71,8 +69,7 @@ homepage: https://railseventstore.org
|
|
71
69
|
licenses:
|
72
70
|
- MIT
|
73
71
|
metadata:
|
74
|
-
homepage_uri: https://railseventstore.org
|
75
|
-
changelog_uri: https://github.com/RailsEventStore/rails_event_store/releases
|
72
|
+
homepage_uri: https://railseventstore.org
|
76
73
|
source_code_uri: https://github.com/RailsEventStore/rails_event_store
|
77
74
|
bug_tracker_uri: https://github.com/RailsEventStore/rails_event_store/issues
|
78
75
|
post_install_message:
|
@@ -83,14 +80,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
83
80
|
requirements:
|
84
81
|
- - ">="
|
85
82
|
- !ruby/object:Gem::Version
|
86
|
-
version: '
|
83
|
+
version: '2.6'
|
87
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
85
|
requirements:
|
89
86
|
- - ">="
|
90
87
|
- !ruby/object:Gem::Version
|
91
88
|
version: '0'
|
92
89
|
requirements: []
|
93
|
-
rubygems_version: 3.0.
|
90
|
+
rubygems_version: 3.0.6
|
94
91
|
signing_key:
|
95
92
|
specification_version: 4
|
96
93
|
summary: Active Record based outbox for Ruby Event Store
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require "sidekiq"
|
2
|
-
|
3
|
-
module RubyEventStore
|
4
|
-
module Outbox
|
5
|
-
class SidekiqMessageHandler
|
6
|
-
def initialize
|
7
|
-
@sidekiq = Sidekiq::Client.new(Sidekiq.redis_pool)
|
8
|
-
end
|
9
|
-
|
10
|
-
def init
|
11
|
-
end
|
12
|
-
|
13
|
-
def handle_one_record(now, record)
|
14
|
-
hash_payload = JSON.parse(record.payload)
|
15
|
-
@sidekiq.__send__(:raw_push, [hash_payload])
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|