tobox 0.6.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d1d0e33f4747993a500d22dddbda2eaf2118e0351342a9d09acdf9b6516f86c
4
- data.tar.gz: e75a3699edf170a1711cc749a8df6ab6b6a4a829057246e1fd690065d89224c5
3
+ metadata.gz: 7fcb3a283fa1bb64036319c64c537891a3c4640331ef96058c0a80f311ff6d9a
4
+ data.tar.gz: e6f6a8cd2b0ec8f38cc5e52added655c1922cc79be890fa79c72df3a56418990
5
5
  SHA512:
6
- metadata.gz: d097b80a68d2ec806f521f0a36113bf74dac00fd0e7080e95496ff0b93a2f8e2e1f594b9d13a4b02e6d094ff260ed839d76bd1116f774c8672c01fda5761f5d6
7
- data.tar.gz: cf138ca863803ae62e165cbd43846c6e35f6b500b344b62fbb1d0a906839cd4d8cc00f720ead1de220dc34802d70baca3a3bae730d01b99fb7d7f550015a6f1e
6
+ metadata.gz: 9b48f7d89bfecba3313b4807fb7cc3139aac28f43c43755657feedddfca7c7fb9048e1b6898becbc3fe05ee9ba28b8a1e57948661743173870ea7b04785a2ddc
7
+ data.tar.gz: 24f01a9794d77d90e406b71be0045c309e7280e46b98ad8aad2375935d47647963780c834833b76a0a4ed838ba5dd95aa184c17e3707059e51cd4ed2f334c932
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.6.1] - 2024-10-30
4
+
5
+ ### Improvements
6
+
7
+ When possible, use `UPDATE FROM outbox RETURNING WHERE (SELECT id .... FOR UPDATE SKIP LOCKED` to fetch-and-update events in one go.
8
+
3
9
  ## [0.6.0] - 2024-10-25
4
10
 
5
11
  ### Features
data/lib/tobox/fetcher.rb CHANGED
@@ -30,8 +30,6 @@ module Tobox
30
30
 
31
31
  @batch_size = configuration[:batch_size]
32
32
 
33
- @mark_as_fetched_params = { attempts: Sequel[@table][:attempts] + 1, last_error: nil }
34
-
35
33
  @before_event_handlers = Array(@configuration.lifecycle_events[:before_event])
36
34
  @after_event_handlers = Array(@configuration.lifecycle_events[:after_event])
37
35
  @error_event_handlers = Array(@configuration.lifecycle_events[:error_event])
@@ -40,16 +38,15 @@ module Tobox
40
38
  def fetch_events(&blk)
41
39
  num_events = 0
42
40
  events_tr do
43
- event_ids = nil
44
- # @type var event_ids: Array[Integer]
41
+ events = nil
42
+ # @type var events: Array[event]?
45
43
 
46
44
  event_id_tr do
47
- event_ids = fetch_event_ids
48
- mark_as_fetched(event_ids) unless event_ids.empty?
45
+ events = do_fetch_events
49
46
  end
50
47
 
51
- if event_ids && !event_ids.empty?
52
- with_events(event_ids) do |events|
48
+ if events && !events.empty?
49
+ with_events(events) do |events|
53
50
  num_events = events.size
54
51
 
55
52
  prepare_events(events, &blk)
@@ -74,11 +71,11 @@ module Tobox
74
71
  def fetch_event_ids
75
72
  @pick_next_sql.for_update
76
73
  .skip_locked
77
- .limit(@batch_size).select_map(:id) # lock starts here
74
+ .limit(@batch_size).select(:id) # lock starts here
78
75
  end
79
76
 
80
- def mark_as_fetched(event_ids)
81
- @ds.where(id: event_ids).update(@mark_as_fetched_params)
77
+ def do_fetch_events
78
+ @ds.where(id: fetch_event_ids).all
82
79
  end
83
80
 
84
81
  def events_tr(&block)
@@ -89,11 +86,11 @@ module Tobox
89
86
  yield
90
87
  end
91
88
 
92
- def with_events(event_ids, &blk)
93
- events, error = yield_events(event_ids, &blk)
89
+ def with_events(events, &blk)
90
+ yield_events(events, &blk)
94
91
 
95
92
  events.each do |event|
96
- event_error = error || event[:error]
93
+ event_error = event[:error]
97
94
  if event_error
98
95
  event.merge!(mark_as_error(event, event_error))
99
96
  handle_error_event(event, event_error)
@@ -103,40 +100,33 @@ module Tobox
103
100
  end
104
101
  end
105
102
 
106
- def yield_events(event_ids)
107
- events_ds = @ds.where(id: event_ids)
108
- events = error = nil
103
+ def yield_events(events)
104
+ unless events.empty?
105
+ errors_by_id = catch(:tobox_batch_errors) do
106
+ yield events
107
+ nil
108
+ end
109
109
 
110
- begin
111
- events = events_ds.all
110
+ # some events from batch errored
111
+ if errors_by_id
112
+ failed = events.values_at(*errors_by_id.keys)
113
+ successful = events - failed
112
114
 
113
- unless events.empty?
114
- errors_by_id = catch(:tobox_batch_errors) do
115
- yield events
116
- nil
115
+ # fill in with batch error
116
+ failed.each do |ev|
117
+ ev[:error] = errors_by_id[events.index(ev)]
117
118
  end
118
119
 
119
- # some events from batch errored
120
- if errors_by_id
121
- failed = events.values_at(*errors_by_id.keys)
122
- successful = events - failed
123
-
124
- # fill in with batch error
125
- failed.each do |ev|
126
- ev[:error] = errors_by_id[events.index(ev)]
127
- end
128
-
129
- # delete successful
130
- @ds.where(id: successful.map { |ev| ev[:id] }).delete unless successful.empty?
131
- else
132
- events_ds.delete
133
- end
120
+ # delete successful
121
+ @ds.where(id: successful.map { |ev| ev[:id] }).delete unless successful.empty?
122
+ else
123
+ @ds.where(id: events.map { |ev| ev[:id] }).delete
134
124
  end
135
- rescue StandardError => e
136
- error = e
137
125
  end
138
-
139
- [events, error]
126
+ rescue StandardError => e
127
+ events.each do |event|
128
+ event[:error] = e
129
+ end
140
130
  end
141
131
 
142
132
  def log_message(msg)
@@ -145,10 +135,8 @@ module Tobox
145
135
 
146
136
  def mark_as_error(event, error)
147
137
  update_params = {
148
- run_at: Sequel.date_add(Sequel::CURRENT_TIMESTAMP,
149
- seconds: @exponential_retry_factor**(event[:attempts] - 1)),
150
- # run_at: Sequel.date_add(Sequel::CURRENT_TIMESTAMP,
151
- # seconds: Sequel.function(:POWER, Sequel[@table][:attempts] + 1, 4)),
138
+ run_at: calculate_event_retry_interval(event[:attempts]),
139
+ attempts: Sequel[@table][:attempts] + 1,
152
140
  last_error: error.full_message(highlight: false)
153
141
  }
154
142
 
@@ -165,6 +153,12 @@ module Tobox
165
153
  end
166
154
  end
167
155
 
156
+ def calculate_event_retry_interval(attempts)
157
+ # Sequel.date_add(Sequel::CURRENT_TIMESTAMP,
158
+ # seconds: Sequel.function(:POWER, Sequel[@table][:attempts] + 1, 4)
159
+ Sequel.date_add(Sequel::CURRENT_TIMESTAMP, seconds: @exponential_retry_factor**attempts)
160
+ end
161
+
168
162
  def to_message(event)
169
163
  {
170
164
  id: event[:id],
@@ -10,13 +10,34 @@ module Tobox
10
10
  module FetcherMethods
11
11
  private
12
12
 
13
- def initialize(_, configuration)
14
- super
13
+ def do_fetch_events
14
+ # mark events as invisible by using run_at as a visibility timeout
15
+ mark_as_fetched_params = {
16
+ run_at: Sequel.date_add(
17
+ Sequel::CURRENT_TIMESTAMP,
18
+ seconds: @configuration[:visibility_timeout]
19
+ ),
20
+ attempts: Sequel[@table][:attempts] + 1,
21
+ last_error: nil
22
+ }
23
+
24
+ if @ds.supports_returning?(:update)
25
+ @ds.where(id: fetch_event_ids).returning.update(mark_as_fetched_params)
26
+ else
27
+ event_ids = fetch_event_ids.select_map(:id)
28
+ events_ds = @ds.where(id: event_ids)
29
+ events_ds.update(mark_as_fetched_params)
30
+ events_ds.first(@batch_size)
31
+ end
32
+ end
15
33
 
16
- @mark_as_fetched_params[:run_at] = Sequel.date_add(
17
- Sequel::CURRENT_TIMESTAMP,
18
- seconds: configuration[:visibility_timeout]
19
- )
34
+ def calculate_event_retry_interval(attempts)
35
+ super(attempts - 1)
36
+ end
37
+
38
+ def set_event_retry_attempts(event, update_params)
39
+ update_params.delete(:attempts)
40
+ super
20
41
  end
21
42
 
22
43
  def events_tr
data/lib/tobox/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tobox
4
- VERSION = "0.6.0"
4
+ VERSION = "0.6.1"
5
5
  end
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.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - HoneyryderChuck
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-25 00:00:00.000000000 Z
11
+ date: 2024-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger