tobox 0.3.2 → 0.4.1
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/CHANGELOG.md +53 -2
- data/README.md +78 -0
- data/lib/tobox/application.rb +9 -2
- data/lib/tobox/cli.rb +3 -3
- data/lib/tobox/configuration.rb +35 -1
- data/lib/tobox/fetcher.rb +1 -7
- data/lib/tobox/plugins/sentry.rb +10 -10
- data/lib/tobox/plugins/stats.rb +123 -0
- data/lib/tobox/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4960d6151461ab6e051605687d99cc69089e498aaea66d97416b92158e48cc4e
|
|
4
|
+
data.tar.gz: e3f2e0a6408696ff1852a484101ca6fa95e5e5e713d1ccb0b829040bb0a748ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ac5d961bc737299d4cd1e3d353955f97b12d984e4b3378b56dbeaf84c5d969ed3b6c02902c70b7ed0fd14230696d44992012d35053565988349b13405f6144ef
|
|
7
|
+
data.tar.gz: 3a921e5ca3f42fa47f8485a0a9bf44c42c31f0f767cfafc81ef1af6d6e43ac83966baffcb20ff28df9c90abb8a4c16e6829c4e9aa9e86ca009ab4fde38a92bd1
|
data/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,64 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.4.1] - 2023-05-24
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
#### `on_database_connect`
|
|
8
|
+
|
|
9
|
+
this adds an extension point for internal sequel database objects, in cases where some tweaks are required (such as in the case of, when using database SSL proxies, setting connection validators).
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
# tobox.rb
|
|
13
|
+
on_database_connect do |db|
|
|
14
|
+
db.extension(:connection_validator)
|
|
15
|
+
end
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## [0.4.0] - 2023-05-19
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
#### `:stats` plugin
|
|
23
|
+
|
|
24
|
+
The `:stats` plugin collects statistics related with the outbox table periodically, and exposes them to app code (which can then relay them to a statsD collector, or similar tool).
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
plugin(:stats)
|
|
29
|
+
on_stats(5) do |stats_collector| # every 5 seconds
|
|
30
|
+
stats = stats_collector.collect
|
|
31
|
+
StatsD.gauge('outbox_pending_backlog', stats[:pending_count])
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Read more about it in [the project README](https://gitlab.com/os85/tobox#stats).
|
|
36
|
+
|
|
37
|
+
#### on_start/on_stop callbacks
|
|
38
|
+
|
|
39
|
+
The `on_start` and `on_stop` callbacks can now be defined in `tobox` configuration:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
# tobox.rb
|
|
43
|
+
on_start do
|
|
44
|
+
puts "tobox is starting..."
|
|
45
|
+
end
|
|
46
|
+
on_stop do
|
|
47
|
+
puts "tobox is stopping..."
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Bugfixes
|
|
52
|
+
|
|
53
|
+
* tobox configuration file is now only loaded after everything else, so access to application code is guaranteed.
|
|
54
|
+
|
|
55
|
+
## [0.3.2] - 2023-03-06
|
|
5
56
|
|
|
6
57
|
### Bugfixes
|
|
7
58
|
|
|
8
59
|
* allow sentry error capture if `report_after_retries` option is turned off.
|
|
9
60
|
|
|
10
|
-
## [0.3.1] -
|
|
61
|
+
## [0.3.1] - 2023-03-03
|
|
11
62
|
|
|
12
63
|
### Bugfixes
|
|
13
64
|
|
data/README.md
CHANGED
|
@@ -20,6 +20,7 @@ Simple, data-first events processing framework based on the [transactional outbo
|
|
|
20
20
|
- [Zeitwerk](#zeitwerk)
|
|
21
21
|
- [Sentry](#sentry)
|
|
22
22
|
- [Datadog](#datadog)
|
|
23
|
+
- [Stats](#stats)
|
|
23
24
|
- [Supported Rubies](#supported-rubies)
|
|
24
25
|
- [Rails support](#rails-support)
|
|
25
26
|
- [Why?](#why)
|
|
@@ -267,6 +268,20 @@ callback executed when an exception was raised in the worker, before processing
|
|
|
267
268
|
on_error_worker { |exception| Sentry.capture_exception(exception) }
|
|
268
269
|
```
|
|
269
270
|
|
|
271
|
+
### `on_database_connect { |db| }`
|
|
272
|
+
|
|
273
|
+
Callback executed right after initializing the `sequel` database object. This can be used, for example, to load database-level extensions and plugins, and set parameters (such as connection pool tweaks). This callback will also be used by plugins which instantiate its own separate database objects (such as in the case of the [stats](#stats) plugin).
|
|
274
|
+
|
|
275
|
+
This callback won't be executed if the database object is created outside of `tobox` configuration parameters.
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
```ruby
|
|
279
|
+
on_database_connect do |db|
|
|
280
|
+
db.extension(:connection_validator)
|
|
281
|
+
db.pool.connection_validation_timeout = -1
|
|
282
|
+
end
|
|
283
|
+
```
|
|
284
|
+
|
|
270
285
|
### `message_to_arguments { |event| }`
|
|
271
286
|
|
|
272
287
|
if exposing raw data to the `on` handlers is not what you'd want, you can always override the behaviour by providing an alternative "before/after fetcher" implementation.
|
|
@@ -482,6 +497,69 @@ end
|
|
|
482
497
|
plugin(:datadog)
|
|
483
498
|
```
|
|
484
499
|
|
|
500
|
+
<a id="markdown-datadog" name="stats"></a>
|
|
501
|
+
### Stats
|
|
502
|
+
|
|
503
|
+
The `stats` plugin collects statistics related with the outbox table periodically, and exposes them to app code (which can then relay them to a statsD collector, or similar tool).
|
|
504
|
+
|
|
505
|
+
```ruby
|
|
506
|
+
plugin(:stats)
|
|
507
|
+
on_stats(5) do |stats_collector| # every 5 seconds
|
|
508
|
+
stats = stats_collector.collect
|
|
509
|
+
#
|
|
510
|
+
# stats => {
|
|
511
|
+
# pending_count: number of new events in the outbox table
|
|
512
|
+
# failing_count: number of events which have failed processing but haven't reached the threshold
|
|
513
|
+
# failed_count: number of events which have failed the max number of tries
|
|
514
|
+
# inbox_count: (if used) number of events marked as received in the inbox table
|
|
515
|
+
# }
|
|
516
|
+
#
|
|
517
|
+
# now you can send them to your statsd collector
|
|
518
|
+
#
|
|
519
|
+
StatsD.gauge('outbox_pending_backlog', stats[:pending_count])
|
|
520
|
+
end
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
#### Bring your own leader election
|
|
524
|
+
|
|
525
|
+
The stats collection runs on every `tobox` initiated. If you're launching it in multiple servers / containers / pods, this means you'll be collecting statistics about the same database on all of these instances. This may not be desirable, and you may want to do this collection in a single instance. This is not a problem that `tobox` can solve by itself, so you'll have to take care of that yourself. Still, here are some cheap recommendations.
|
|
526
|
+
|
|
527
|
+
##### Postgres advisory locks
|
|
528
|
+
|
|
529
|
+
If your database is PostgreSQL, you can leverage session-level [advisory locks](https://www.postgresql.org/docs/current/explicit-locking.html#ADVISORY-LOCKS) to ensure single-instance access to this functionality. `tobox` also exposes the database instance to the `on_stats` callback:
|
|
530
|
+
|
|
531
|
+
```ruby
|
|
532
|
+
c.on_stats(5) do |stats_collector, db|
|
|
533
|
+
if db.get(Sequel.function(:pg_try_advisory_lock, 1))
|
|
534
|
+
stats = stats_collector.collect
|
|
535
|
+
StatsD.gauge('outbox_pending_backlog', stats[:pending_count])
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
If a server goes down, one of the remaining ones will acquire the lock and ensure stats processing.
|
|
541
|
+
|
|
542
|
+
##### Redis distributed locks
|
|
543
|
+
|
|
544
|
+
If you're already using [redis](https://redis.io/), you can use its distributed lock feature to achieve the goal:
|
|
545
|
+
|
|
546
|
+
```ruby
|
|
547
|
+
# using redlock
|
|
548
|
+
c.on_stats(5) do |stats_collector, db|
|
|
549
|
+
begin
|
|
550
|
+
lock_info = lock_manager.lock("outbox", 5000)
|
|
551
|
+
|
|
552
|
+
stats = stats_collector.collect
|
|
553
|
+
StatsD.gauge('outbox_pending_backlog', stats[:pending_count])
|
|
554
|
+
|
|
555
|
+
# extend to hold the lock for the next loop
|
|
556
|
+
lock_info = lock_manager.lock("outbox", 5000, extend: lock_info)
|
|
557
|
+
rescue Redlock::LockError
|
|
558
|
+
# some other server already has the lock, try later
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
```
|
|
562
|
+
|
|
485
563
|
<a id="markdown-supported-rubies" name="supported-rubies"></a>
|
|
486
564
|
## Supported Rubies
|
|
487
565
|
|
data/lib/tobox/application.rb
CHANGED
|
@@ -6,18 +6,23 @@ module Tobox
|
|
|
6
6
|
@configuration = configuration
|
|
7
7
|
@running = false
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
@on_start_handlers = Array(configuration.lifecycle_events[:on_start])
|
|
10
|
+
@on_stop_handlers = Array(configuration.lifecycle_events[:on_stop])
|
|
11
|
+
|
|
12
|
+
worker = configuration[:worker]
|
|
10
13
|
|
|
11
14
|
@pool = case worker
|
|
12
15
|
when :thread then ThreadedPool
|
|
13
16
|
when :fiber then FiberPool
|
|
14
17
|
else worker
|
|
15
|
-
end.new(
|
|
18
|
+
end.new(configuration)
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
def start
|
|
19
22
|
return if @running
|
|
20
23
|
|
|
24
|
+
@on_start_handlers.each(&:call)
|
|
25
|
+
|
|
21
26
|
@pool.start
|
|
22
27
|
@running = true
|
|
23
28
|
end
|
|
@@ -25,6 +30,8 @@ module Tobox
|
|
|
25
30
|
def stop
|
|
26
31
|
return unless @running
|
|
27
32
|
|
|
33
|
+
@on_stop_handlers.each(&:call)
|
|
34
|
+
|
|
28
35
|
@pool.stop
|
|
29
36
|
|
|
30
37
|
@running = false
|
data/lib/tobox/cli.rb
CHANGED
|
@@ -18,15 +18,15 @@ module Tobox
|
|
|
18
18
|
def run
|
|
19
19
|
options = @options
|
|
20
20
|
|
|
21
|
+
# boot
|
|
22
|
+
options.fetch(:require).each(&method(:require))
|
|
23
|
+
|
|
21
24
|
config = Configuration.new do |c|
|
|
22
25
|
c.instance_eval(File.read(options.fetch(:config_file)), options.fetch(:config_file), 1)
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
logger = config.default_logger
|
|
26
29
|
|
|
27
|
-
# boot
|
|
28
|
-
options.fetch(:require).each(&method(:require))
|
|
29
|
-
|
|
30
30
|
# signals
|
|
31
31
|
pipe_read, pipe_write = IO.pipe
|
|
32
32
|
%w[INT TERM].each do |sig|
|
data/lib/tobox/configuration.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Tobox
|
|
|
7
7
|
class Configuration
|
|
8
8
|
extend Forwardable
|
|
9
9
|
|
|
10
|
-
attr_reader :handlers, :lifecycle_events, :arguments_handler, :default_logger
|
|
10
|
+
attr_reader :handlers, :lifecycle_events, :arguments_handler, :default_logger, :database
|
|
11
11
|
|
|
12
12
|
def_delegator :@config, :[]
|
|
13
13
|
|
|
@@ -60,6 +60,24 @@ module Tobox
|
|
|
60
60
|
@default_logger = @config[:logger] || Logger.new(STDERR, formatter: DEFAULT_LOG_FORMATTER) # rubocop:disable Style/GlobalStdStream
|
|
61
61
|
@default_logger.level = @config[:log_level] || (env == "production" ? Logger::INFO : Logger::DEBUG)
|
|
62
62
|
|
|
63
|
+
@database = if @config[:database_uri]
|
|
64
|
+
database_opts = {}
|
|
65
|
+
database_opts[:max_connections] = @config[:concurrency] if @config[:worker] == :thread
|
|
66
|
+
db = Sequel.connect(@config[:database_uri].to_s, database_opts)
|
|
67
|
+
Array(@lifecycle_events[:database_connect]).each { |cb| cb.call(db) }
|
|
68
|
+
db
|
|
69
|
+
else
|
|
70
|
+
Sequel::DATABASES.first
|
|
71
|
+
end
|
|
72
|
+
raise Error, "no database found" unless @database
|
|
73
|
+
|
|
74
|
+
if @database.frozen?
|
|
75
|
+
raise "#{@database} must have the :date_arithmetic extension loaded" unless Sequel.respond_to?(:date_add)
|
|
76
|
+
else
|
|
77
|
+
@database.extension :date_arithmetic
|
|
78
|
+
@database.loggers << @default_logger unless @config[:environment] == "production"
|
|
79
|
+
end
|
|
80
|
+
|
|
63
81
|
freeze
|
|
64
82
|
end
|
|
65
83
|
|
|
@@ -70,6 +88,16 @@ module Tobox
|
|
|
70
88
|
self
|
|
71
89
|
end
|
|
72
90
|
|
|
91
|
+
def on_start(&callback)
|
|
92
|
+
(@lifecycle_events[:on_start] ||= []) << callback
|
|
93
|
+
self
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def on_stop(&callback)
|
|
97
|
+
(@lifecycle_events[:on_stop] ||= []) << callback
|
|
98
|
+
self
|
|
99
|
+
end
|
|
100
|
+
|
|
73
101
|
def on_before_event(&callback)
|
|
74
102
|
(@lifecycle_events[:before_event] ||= []) << callback
|
|
75
103
|
self
|
|
@@ -90,6 +118,11 @@ module Tobox
|
|
|
90
118
|
self
|
|
91
119
|
end
|
|
92
120
|
|
|
121
|
+
def on_database_connect(&callback)
|
|
122
|
+
(@lifecycle_events[:database_connect] ||= []) << callback
|
|
123
|
+
self
|
|
124
|
+
end
|
|
125
|
+
|
|
93
126
|
def message_to_arguments(&callback)
|
|
94
127
|
@arguments_handler = callback
|
|
95
128
|
self
|
|
@@ -116,6 +149,7 @@ module Tobox
|
|
|
116
149
|
@handlers.each_value(&:freeze).freeze
|
|
117
150
|
@lifecycle_events.each_value(&:freeze).freeze
|
|
118
151
|
@plugins.freeze
|
|
152
|
+
@database.freeze
|
|
119
153
|
super
|
|
120
154
|
end
|
|
121
155
|
|
data/lib/tobox/fetcher.rb
CHANGED
|
@@ -10,13 +10,7 @@ module Tobox
|
|
|
10
10
|
|
|
11
11
|
@logger = @configuration.default_logger
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
@db = database_uri ? Sequel.connect(database_uri.to_s) : Sequel::DATABASES.first
|
|
15
|
-
raise Error, "no database found" unless @db
|
|
16
|
-
|
|
17
|
-
@db.extension :date_arithmetic
|
|
18
|
-
|
|
19
|
-
@db.loggers << @logger unless @configuration[:environment] == "production"
|
|
13
|
+
@db = configuration.database
|
|
20
14
|
|
|
21
15
|
@table = configuration[:table]
|
|
22
16
|
@group_column = configuration[:group_column]
|
data/lib/tobox/plugins/sentry.rb
CHANGED
|
@@ -30,16 +30,16 @@ module Tobox
|
|
|
30
30
|
|
|
31
31
|
scope = ::Sentry.get_current_scope
|
|
32
32
|
|
|
33
|
-
scope.set_contexts(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
scope.set_contexts(tobox: {
|
|
34
|
+
id: event[:id],
|
|
35
|
+
type: event[:type],
|
|
36
|
+
attempts: event[:attempts],
|
|
37
|
+
created_at: event[:created_at],
|
|
38
|
+
run_at: event[:run_at],
|
|
39
|
+
last_error: event[:last_error]&.byteslice(0..1000),
|
|
40
|
+
version: Tobox::VERSION,
|
|
41
|
+
db_adapter: @db_scheme
|
|
42
|
+
})
|
|
43
43
|
scope.set_tags(
|
|
44
44
|
outbox: @db_table,
|
|
45
45
|
event_id: event[:id],
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tobox
|
|
4
|
+
module Plugins
|
|
5
|
+
module Stats
|
|
6
|
+
module ConfigurationMethods
|
|
7
|
+
attr_reader :stats_interval_seconds
|
|
8
|
+
|
|
9
|
+
def on_stats(stats_interval_seconds, &callback)
|
|
10
|
+
@stats_interval_seconds = stats_interval_seconds
|
|
11
|
+
|
|
12
|
+
(@lifecycle_events[:stats] ||= []) << callback
|
|
13
|
+
self
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class StatsEmitter
|
|
18
|
+
def initialize(config)
|
|
19
|
+
@config = config
|
|
20
|
+
@running = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def start
|
|
24
|
+
return if @running
|
|
25
|
+
|
|
26
|
+
config = @config
|
|
27
|
+
|
|
28
|
+
interval = config.stats_interval_seconds
|
|
29
|
+
@stats_handlers = Array(config.lifecycle_events[:stats])
|
|
30
|
+
|
|
31
|
+
return if @stats_handlers.empty?
|
|
32
|
+
|
|
33
|
+
@error_handlers = Array(config.lifecycle_events[:error_worker])
|
|
34
|
+
|
|
35
|
+
@max_attempts = config[:max_attempts]
|
|
36
|
+
|
|
37
|
+
@db = Sequel.connect(config.database.opts.merge(single_threaded: true))
|
|
38
|
+
Array(config.lifecycle_events[:database_connect]).each { |cb| cb.call(@db) }
|
|
39
|
+
|
|
40
|
+
@outbox_table = config[:table]
|
|
41
|
+
@outbox_ds = @db[@outbox_table]
|
|
42
|
+
|
|
43
|
+
inbox_table = config[:inbox_table]
|
|
44
|
+
@inbox_ds = @db[inbox_table] if inbox_table
|
|
45
|
+
|
|
46
|
+
logger = config.default_logger
|
|
47
|
+
|
|
48
|
+
stats = method(:collect_event_stats)
|
|
49
|
+
stats.instance_eval do
|
|
50
|
+
alias collect call
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@th = Thread.start do
|
|
54
|
+
Thread.current.name = "outbox-stats"
|
|
55
|
+
|
|
56
|
+
loop do
|
|
57
|
+
logger.debug { "stats worker: sleep for #{interval}s..." }
|
|
58
|
+
sleep interval
|
|
59
|
+
|
|
60
|
+
begin
|
|
61
|
+
emit_event_stats(stats)
|
|
62
|
+
rescue RuntimeError => e
|
|
63
|
+
@error_handlers.each { |hd| hd.call(e) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
break unless @running
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
@running = true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def stop
|
|
74
|
+
return unless @running
|
|
75
|
+
|
|
76
|
+
@th.terminate
|
|
77
|
+
|
|
78
|
+
@db.disconnect
|
|
79
|
+
|
|
80
|
+
@running = false
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def emit_event_stats(stats)
|
|
86
|
+
@stats_handlers.each do |hd|
|
|
87
|
+
hd.call(stats, @db)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def collect_event_stats
|
|
92
|
+
stats = @outbox_ds.group_and_count(
|
|
93
|
+
Sequel.case([
|
|
94
|
+
[{ last_error: nil }, "pending_count"],
|
|
95
|
+
[Sequel.expr([:attempts]) < @max_attempts, "failing_count"]
|
|
96
|
+
],
|
|
97
|
+
"failed_count").as(:status)
|
|
98
|
+
)
|
|
99
|
+
stats = stats.as_hash(:status, :count).transform_keys(&:to_sym)
|
|
100
|
+
|
|
101
|
+
# fill it in
|
|
102
|
+
stats[:pending_count] ||= 0
|
|
103
|
+
stats[:failing_count] ||= 0
|
|
104
|
+
stats[:failed_count] ||= 0
|
|
105
|
+
|
|
106
|
+
stats[:inbox_count] = @inbox_ds.count if @inbox_ds
|
|
107
|
+
stats
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
class << self
|
|
112
|
+
def configure(config)
|
|
113
|
+
emitter = StatsEmitter.new(config)
|
|
114
|
+
|
|
115
|
+
config.on_start(&emitter.method(:start))
|
|
116
|
+
config.on_stop(&emitter.method(:stop))
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
register_plugin :stats, Stats
|
|
122
|
+
end
|
|
123
|
+
end
|
data/lib/tobox/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tobox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- HoneyryderChuck
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-05-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: sequel
|
|
@@ -46,6 +46,7 @@ files:
|
|
|
46
46
|
- lib/tobox/plugins/datadog/integration.rb
|
|
47
47
|
- lib/tobox/plugins/datadog/patcher.rb
|
|
48
48
|
- lib/tobox/plugins/sentry.rb
|
|
49
|
+
- lib/tobox/plugins/stats.rb
|
|
49
50
|
- lib/tobox/plugins/zeitwerk.rb
|
|
50
51
|
- lib/tobox/pool.rb
|
|
51
52
|
- lib/tobox/pool/fiber_pool.rb
|
|
@@ -77,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
77
78
|
- !ruby/object:Gem::Version
|
|
78
79
|
version: '0'
|
|
79
80
|
requirements: []
|
|
80
|
-
rubygems_version: 3.
|
|
81
|
+
rubygems_version: 3.4.6
|
|
81
82
|
signing_key:
|
|
82
83
|
specification_version: 4
|
|
83
84
|
summary: Transactional outbox pattern implementation in ruby
|