tobox 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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