tobox 0.7.1 → 0.7.2
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 +11 -0
- data/README.md +11 -0
- data/lib/tobox/fetcher.rb +3 -3
- data/lib/tobox/plugins/event_grouping.rb +5 -5
- data/lib/tobox/plugins/progress.rb +25 -9
- data/lib/tobox/plugins/sentry.rb +2 -2
- data/lib/tobox/pool/fiber_pool.rb +10 -4
- data/lib/tobox/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 565eb7ae45be10c2048e62cb9b2e3b85787e80bba0b07917ba169016d347274b
|
|
4
|
+
data.tar.gz: 5a235f35084ab94d83d14be26d8ddb75d1a77582998f6bdf39ecf176052f308e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8548a5fa78246b4d2be197c0f9b2a7d606f4b74c0205622d85e12d54cf649152dcce400668cce0cfc4c2cbcc2ce5ea729e6242f5e918ff989009a2188decc0d9
|
|
7
|
+
data.tar.gz: b377e117f8d1424118efb080dc9df5c22c17c7d2d087d231a52425c4e2166009f2e09fe90e1a5f95aeb58c19120010e77c7225547b0295ebaba2d6f4aa3f1b29
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.7.2] - 2026-02-03
|
|
4
|
+
|
|
5
|
+
### Improvements
|
|
6
|
+
|
|
7
|
+
* Added support for SQLite as a backend.
|
|
8
|
+
|
|
9
|
+
### Bugfixes
|
|
10
|
+
|
|
11
|
+
* Fixed `sentry` plugin to work with the `sentry-ruby` sdk v6.
|
|
12
|
+
* `:progress` plugin: when using postgresql, the "UPDATE with subquery" used to fetch-and-mark a job to process will use a CTE instead, in order to avoid a known issue with the former where the query planner may decide to scan over the entries of the subquery and cause more UPDATEs than intended when the subquery has a LIMIT.
|
|
13
|
+
|
|
3
14
|
## [0.7.1] - 2025-02-07
|
|
4
15
|
|
|
5
16
|
* `:datadog` plugin: support datadog gem v2 or higher.
|
data/README.md
CHANGED
|
@@ -43,6 +43,8 @@ Simple, data-first events processing framework based on the [transactional outbo
|
|
|
43
43
|
* Oracle
|
|
44
44
|
* Microsoft SQL Server
|
|
45
45
|
|
|
46
|
+
`tobox` supports `sqlite` as well, despite its lack of `SKIP LOCKED`, due to the caveat of write operations being performed one-at-a-time.
|
|
47
|
+
|
|
46
48
|
<a id="markdown-installation" name="installation"></a>
|
|
47
49
|
## Installation
|
|
48
50
|
|
|
@@ -456,6 +458,13 @@ end
|
|
|
456
458
|
|
|
457
459
|
Timeout (in seconds) after which a previously marked-for-consumption event can be retried (default: `30`)
|
|
458
460
|
|
|
461
|
+
##### `cte_table`
|
|
462
|
+
|
|
463
|
+
the name of the CTE table used in the query to fetch jobs (`:outbox_cte` by default).
|
|
464
|
+
|
|
465
|
+
(This option is only used when the database is PostgreSQL).
|
|
466
|
+
|
|
467
|
+
|
|
459
468
|
<a id="markdown-event-grouping" name="event-grouping"></a>
|
|
460
469
|
### Event grouping
|
|
461
470
|
|
|
@@ -604,6 +613,8 @@ on_sentry_init do |sentry_cfg|
|
|
|
604
613
|
end
|
|
605
614
|
```
|
|
606
615
|
|
|
616
|
+
This plugin also supports [Sentry transactions](https://docs.sentry.io/product/insights/overview/transaction-summary/), however you're required to be using v6 or higher.
|
|
617
|
+
|
|
607
618
|
<a id="markdown-datadog" name="datadog"></a>
|
|
608
619
|
### Datadog
|
|
609
620
|
|
data/lib/tobox/fetcher.rb
CHANGED
|
@@ -82,9 +82,9 @@ module Tobox
|
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def fetch_event_ids
|
|
85
|
-
@pick_next_sql
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
ds = @pick_next_sql
|
|
86
|
+
ds = ds.for_update.skip_locked if ds.supports_skip_locked?
|
|
87
|
+
ds.limit(@batch_size).select(:id) # lock starts here
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def do_fetch_events
|
|
@@ -17,10 +17,9 @@ module Tobox
|
|
|
17
17
|
private
|
|
18
18
|
|
|
19
19
|
def fetch_event_ids
|
|
20
|
-
group = @pick_next_sql
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
.select(@group_column)
|
|
20
|
+
group = @pick_next_sql
|
|
21
|
+
group = group.for_update.skip_locked if group.supports_skip_locked?
|
|
22
|
+
group = group.limit(1).select(@group_column)
|
|
24
23
|
|
|
25
24
|
# get total from a group, to compare to the number of future locked rows.
|
|
26
25
|
total_from_group = @ds.where(@group_column => group).count
|
|
@@ -33,7 +32,8 @@ module Tobox
|
|
|
33
32
|
event_ids.order(Sequel.desc(@visibility_column, nulls: :first), :id)
|
|
34
33
|
end
|
|
35
34
|
|
|
36
|
-
event_ids = event_ids.for_update.skip_locked.
|
|
35
|
+
event_ids = event_ids.for_update.skip_locked if event_ids.supports_skip_locked?
|
|
36
|
+
event_ids = event_ids.select_map(:id)
|
|
37
37
|
|
|
38
38
|
if event_ids.size != total_from_group
|
|
39
39
|
# this happens if concurrent workers locked different rows from the same group,
|
|
@@ -4,10 +4,17 @@ module Tobox
|
|
|
4
4
|
module Plugins
|
|
5
5
|
module Progress
|
|
6
6
|
def self.configure(conf)
|
|
7
|
+
conf.config[:cte_table] = :outbox_cte
|
|
7
8
|
conf.config[:visibility_timeout] = 30
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
module FetcherMethods
|
|
12
|
+
def initialize(_, configuration)
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
@cte_table = configuration[:cte_table]
|
|
16
|
+
end
|
|
17
|
+
|
|
11
18
|
private
|
|
12
19
|
|
|
13
20
|
def do_fetch_events
|
|
@@ -19,17 +26,26 @@ module Tobox
|
|
|
19
26
|
}
|
|
20
27
|
mark_as_fetched_params[@attempts_column] = Sequel[@table][@attempts_column] + 1 if @attempts_column
|
|
21
28
|
|
|
22
|
-
mark_as_fetched_params[@visibility_column] =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Sequel::CURRENT_TIMESTAMP,
|
|
27
|
-
seconds: @configuration[:visibility_timeout]
|
|
28
|
-
)
|
|
29
|
-
end
|
|
29
|
+
mark_as_fetched_params[@visibility_column] = (@configuration.visibility_type_bool? || Sequel.date_add(
|
|
30
|
+
Sequel::CURRENT_TIMESTAMP,
|
|
31
|
+
seconds: @configuration[:visibility_timeout]
|
|
32
|
+
))
|
|
30
33
|
|
|
31
34
|
if @ds.supports_returning?(:update)
|
|
32
|
-
|
|
35
|
+
ids = fetch_event_ids
|
|
36
|
+
ids = if @db.database_type == :postgres && @ds.supports_cte?(:update)
|
|
37
|
+
# The Postgres planner can ignore a LIMIT in the subquery, causing more UPDATEs than LIMIT.
|
|
38
|
+
# A know solution or workaround is to use a CTE as an "optimization fence".
|
|
39
|
+
# https://dba.stackexchange.com/questions/69471/postgres-update-limit-1/69497#69497
|
|
40
|
+
ds = @ds.with(@cte_table, ids.select(:id))
|
|
41
|
+
.from(@table, @cte_table)
|
|
42
|
+
.where(Sequel[@cte_table][:id] => Sequel[@table][:id])
|
|
43
|
+
ds = ds.where(Sequel[@table][@attempts_column] < @configuration[:max_attempts]) if @attempts_column
|
|
44
|
+
ds
|
|
45
|
+
else
|
|
46
|
+
@ds.where(id: ids)
|
|
47
|
+
end
|
|
48
|
+
ids.returning.update(mark_as_fetched_params)
|
|
33
49
|
else
|
|
34
50
|
event_ids = fetch_event_ids.select_map(:id)
|
|
35
51
|
events_ds = @ds.where(id: event_ids)
|
data/lib/tobox/plugins/sentry.rb
CHANGED
|
@@ -55,7 +55,7 @@ module Tobox
|
|
|
55
55
|
|
|
56
56
|
scope.set_transaction_name("#{TOBOX_NAME}/#{event[:type]}") unless scope.transaction_name
|
|
57
57
|
|
|
58
|
-
transaction = start_transaction(scope.transaction_name, event[:metadata].to_h
|
|
58
|
+
transaction = start_transaction(scope.transaction_name, event[:metadata].to_h)
|
|
59
59
|
|
|
60
60
|
return unless transaction
|
|
61
61
|
|
|
@@ -94,7 +94,7 @@ module Tobox
|
|
|
94
94
|
|
|
95
95
|
def start_transaction(transaction_name, sentry_trace)
|
|
96
96
|
options = { name: transaction_name, op: "tobox" }
|
|
97
|
-
transaction = ::Sentry
|
|
97
|
+
transaction = ::Sentry.continue_trace(sentry_trace, **options) unless sentry_trace.empty?
|
|
98
98
|
::Sentry.start_transaction(transaction: transaction, **options)
|
|
99
99
|
end
|
|
100
100
|
|
|
@@ -52,10 +52,16 @@ module Tobox
|
|
|
52
52
|
|
|
53
53
|
return unless th.alive?
|
|
54
54
|
|
|
55
|
-
th.
|
|
56
|
-
th.
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
th.report_on_exception = false
|
|
56
|
+
th.abort_on_exception = false
|
|
57
|
+
begin
|
|
58
|
+
th.raise(KillError)
|
|
59
|
+
th.join(grace_shutdown_timeout)
|
|
60
|
+
th.kill
|
|
61
|
+
th.join(1)
|
|
62
|
+
rescue KillError
|
|
63
|
+
# async re-raises the interrupt error
|
|
64
|
+
end
|
|
59
65
|
end
|
|
60
66
|
|
|
61
67
|
private
|
data/lib/tobox/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tobox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- HoneyryderChuck
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: logger
|
|
@@ -94,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '0'
|
|
96
96
|
requirements: []
|
|
97
|
-
rubygems_version: 3.6.
|
|
97
|
+
rubygems_version: 3.6.9
|
|
98
98
|
specification_version: 4
|
|
99
99
|
summary: Transactional outbox pattern implementation in ruby
|
|
100
100
|
test_files: []
|