tobox 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +5 -0
- data/lib/tobox/cli.rb +7 -1
- data/lib/tobox/configuration.rb +1 -0
- data/lib/tobox/fetcher.rb +26 -37
- data/lib/tobox/plugins/event_grouping.rb +2 -2
- data/lib/tobox/plugins/progress.rb +1 -1
- data/lib/tobox/pool/fiber_pool.rb +50 -10
- data/lib/tobox/pool/threaded_pool.rb +20 -11
- data/lib/tobox/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15d95687a102c98fcc33859b3a369dc9026f04fa58f7f785bcad1d9ccb40010f
|
4
|
+
data.tar.gz: 656b296f9d72d67877945317d4a6d5505de63044f74e08c506970b2c841599f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 172b54fd340f865dbc26a30266f815fe556424cd150c8205c872da02d3725def786648710097b0880de41cc16940a39bd34c8592049d22a907d527ff84b26a3a
|
7
|
+
data.tar.gz: 1dafbf50e8d18c4eb7f4dfd31539322230bd1d11d403f250e4612a0579e878c366fe6b2d44eb24ae17f32476bd25994457563d3fd5ef1a46d7499dc92a93ee1d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.5.1] - 2024-09-26
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* Refactoring of management of event id which replaces `SELECT id IN (?)` resulting queries with `SELECT id = ?`.
|
8
|
+
* Process shutdown is now more predictable, also in the grace period.
|
9
|
+
* `grace_shutdown_timeout` is a new configuration, by default 5 (seconds).
|
10
|
+
|
3
11
|
## [0.5.0] - 2024-09-16
|
4
12
|
|
5
13
|
### Features
|
data/README.md
CHANGED
@@ -241,6 +241,10 @@ Time (in seconds) to wait before checking again for events in the outbox.
|
|
241
241
|
|
242
242
|
Time (in seconds) to wait for events to finishing processing, before hard-killing the process.
|
243
243
|
|
244
|
+
### `grace_shutdown_timeout`
|
245
|
+
|
246
|
+
Grace period (in seconds) to wait after, hard-killing the work in progress, and before exiting the process.
|
247
|
+
|
244
248
|
### `on(event_type) { |before, after| }`
|
245
249
|
|
246
250
|
callback executed when processing an event of the given type. By default, it'll yield the state of data before and after the event (unless `message_to_arguments` is set).
|
@@ -583,6 +587,7 @@ on_stats(5) do |stats_collector| # every 5 seconds
|
|
583
587
|
# now you can send them to your statsd collector
|
584
588
|
#
|
585
589
|
StatsD.gauge('outbox_pending_backlog', stats[:pending_count])
|
590
|
+
StatsD.gauge('outbox_oldest_message_age', stats[:oldest_event_age_in_seconds])
|
586
591
|
end
|
587
592
|
```
|
588
593
|
|
data/lib/tobox/cli.rb
CHANGED
@@ -108,12 +108,18 @@ module Tobox
|
|
108
108
|
opts[:tag] = arg
|
109
109
|
end
|
110
110
|
|
111
|
-
o.on "-t", "--shutdown-timeout NUM",
|
111
|
+
o.on "-t", "--shutdown-timeout NUM", Float, "Shutdown timeout (in seconds)" do |arg|
|
112
112
|
raise ArgumentError, "must be positive" unless arg.positive?
|
113
113
|
|
114
114
|
opts[:shutdown_timeout] = arg
|
115
115
|
end
|
116
116
|
|
117
|
+
o.on "-g", "--shutdown-grace-timeout NUM", Float, "Shutdown grace timeout (in seconds)" do |arg|
|
118
|
+
raise ArgumentError, "must be positive" unless arg.positive?
|
119
|
+
|
120
|
+
opts[:grace_shutdown_timeout] = arg
|
121
|
+
end
|
122
|
+
|
117
123
|
o.on "--verbose", "Print more verbose output" do |arg|
|
118
124
|
opts[:verbose] = arg
|
119
125
|
end
|
data/lib/tobox/configuration.rb
CHANGED
data/lib/tobox/fetcher.rb
CHANGED
@@ -38,27 +38,20 @@ module Tobox
|
|
38
38
|
def fetch_events(&blk)
|
39
39
|
num_events = 0
|
40
40
|
events_tr do
|
41
|
-
|
41
|
+
event_id = nil
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
mark_as_fetched(
|
43
|
+
event_id_tr do
|
44
|
+
event_id = fetch_event_id
|
45
|
+
mark_as_fetched(event_id) if event_id
|
46
46
|
end
|
47
47
|
|
48
|
-
|
48
|
+
if event_id
|
49
|
+
with_event(event_id) do |event|
|
50
|
+
num_events = 1
|
49
51
|
|
50
|
-
|
51
|
-
with_events(event_ids) do |events|
|
52
|
-
evts = events
|
53
|
-
num_events = events.count
|
54
|
-
|
55
|
-
evts = events.filter_map do |ev|
|
56
|
-
prepare_event(ev, &blk)
|
57
|
-
end
|
52
|
+
prepare_event(event, &blk)
|
58
53
|
end
|
59
54
|
end
|
60
|
-
|
61
|
-
return 0 if evts.nil?
|
62
55
|
end
|
63
56
|
|
64
57
|
num_events
|
@@ -70,56 +63,52 @@ module Tobox
|
|
70
63
|
event[:metadata] = try_json_parse(event[:metadata])
|
71
64
|
handle_before_event(event)
|
72
65
|
yield(to_message(event))
|
73
|
-
event
|
74
66
|
end
|
75
67
|
|
76
|
-
def
|
68
|
+
def fetch_event_id
|
77
69
|
@pick_next_sql.for_update
|
78
70
|
.skip_locked
|
79
|
-
.limit(1).select_map(:id) # lock starts here
|
71
|
+
.limit(1).select_map(:id).first # lock starts here
|
80
72
|
end
|
81
73
|
|
82
|
-
def mark_as_fetched(
|
83
|
-
@ds.where(id:
|
74
|
+
def mark_as_fetched(event_id)
|
75
|
+
@ds.where(id: event_id).update(@mark_as_fetched_params)
|
84
76
|
end
|
85
77
|
|
86
78
|
def events_tr(&block)
|
87
79
|
@db.transaction(savepoint: false, &block)
|
88
80
|
end
|
89
81
|
|
90
|
-
def
|
82
|
+
def event_id_tr
|
91
83
|
yield
|
92
84
|
end
|
93
85
|
|
94
|
-
def
|
95
|
-
|
86
|
+
def with_event(event_id, &blk)
|
87
|
+
event, error = yield_event(event_id, &blk)
|
96
88
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
handle_after_event(event)
|
103
|
-
end
|
89
|
+
if error
|
90
|
+
event.merge!(mark_as_error(event, error))
|
91
|
+
handle_error_event(event, error)
|
92
|
+
else
|
93
|
+
handle_after_event(event)
|
104
94
|
end
|
105
95
|
end
|
106
96
|
|
107
|
-
def
|
108
|
-
events_ds = @ds.where(id:
|
109
|
-
|
110
|
-
error = nil
|
97
|
+
def yield_event(event_id)
|
98
|
+
events_ds = @ds.where(id: event_id)
|
99
|
+
event = error = nil
|
111
100
|
|
112
101
|
begin
|
113
|
-
|
102
|
+
event = events_ds.first
|
114
103
|
|
115
|
-
yield
|
104
|
+
yield event
|
116
105
|
|
117
106
|
events_ds.delete
|
118
107
|
rescue StandardError => e
|
119
108
|
error = e
|
120
109
|
end
|
121
110
|
|
122
|
-
[
|
111
|
+
[event, error]
|
123
112
|
end
|
124
113
|
|
125
114
|
def log_message(msg)
|
@@ -16,7 +16,7 @@ module Tobox
|
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
-
def
|
19
|
+
def fetch_event_id
|
20
20
|
group = @pick_next_sql.for_update
|
21
21
|
.skip_locked
|
22
22
|
.limit(1)
|
@@ -37,7 +37,7 @@ module Tobox
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# lock all, process 1
|
40
|
-
event_ids
|
40
|
+
event_ids.first
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -5,34 +5,74 @@ require "fiber_scheduler"
|
|
5
5
|
|
6
6
|
module Tobox
|
7
7
|
class FiberPool < Pool
|
8
|
-
def initialize(
|
8
|
+
def initialize(_)
|
9
9
|
Sequel.extension(:fiber_concurrency)
|
10
10
|
super
|
11
|
+
@fibers = []
|
12
|
+
|
13
|
+
@fiber_mtx = Mutex.new
|
14
|
+
@fiber_cond = ConditionVariable.new
|
15
|
+
@fiber_thread = nil
|
11
16
|
end
|
12
17
|
|
13
18
|
def start
|
14
19
|
@fiber_thread = Thread.start do
|
15
20
|
Thread.current.name = "tobox-fibers-thread"
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
begin
|
23
|
+
FiberScheduler do
|
24
|
+
@fiber_mtx.synchronize do
|
25
|
+
@workers.each do |worker|
|
26
|
+
@fibers << start_fiber_worker(worker)
|
27
|
+
end
|
28
|
+
@fiber_cond.signal
|
29
|
+
end
|
20
30
|
end
|
31
|
+
rescue KillError
|
32
|
+
@fibers.each { |f| f.raise(KillError) }
|
21
33
|
end
|
22
34
|
end
|
35
|
+
@fiber_mtx.synchronize do
|
36
|
+
@fiber_cond.wait(@fiber_mtx)
|
37
|
+
end
|
23
38
|
end
|
24
39
|
|
25
40
|
def stop
|
26
41
|
shutdown_timeout = @configuration[:shutdown_timeout]
|
42
|
+
grace_shutdown_timeout = @configuration[:grace_shutdown_timeout]
|
27
43
|
|
28
44
|
super
|
29
45
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
46
|
+
@fiber_thread.join(shutdown_timeout)
|
47
|
+
|
48
|
+
return unless @fiber_thread.alive?
|
49
|
+
|
50
|
+
@fiber_thread.raise(KillError)
|
51
|
+
@fiber_thread.join(grace_shutdown_timeout)
|
52
|
+
@fiber_thread.kill
|
53
|
+
@fiber_thread.join(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def start_fiber_worker(worker)
|
59
|
+
Fiber.schedule do
|
60
|
+
do_work(worker)
|
61
|
+
|
62
|
+
@fiber_mtx.synchronize do
|
63
|
+
@fibers.delete(Fiber.current)
|
64
|
+
|
65
|
+
if worker.finished? && @running
|
66
|
+
idx = @workers.index(worker)
|
67
|
+
|
68
|
+
raise Error, "worker not found" unless idx
|
69
|
+
|
70
|
+
subst_worker = Worker.new(worker.label, @configuration)
|
71
|
+
@workers[idx] = subst_worker
|
72
|
+
subst_fiber = start_fiber_worker(subst_worker)
|
73
|
+
@fiber_mtx.synchronize { @fibers << subst_fiber }
|
74
|
+
end
|
75
|
+
end
|
36
76
|
end
|
37
77
|
end
|
38
78
|
end
|
@@ -22,24 +22,35 @@ module Tobox
|
|
22
22
|
|
23
23
|
def stop
|
24
24
|
shutdown_timeout = @configuration[:shutdown_timeout]
|
25
|
-
|
26
|
-
deadline = Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
25
|
+
grace_shutdown_timeout = @configuration[:grace_shutdown_timeout]
|
27
26
|
|
28
27
|
super
|
29
28
|
Thread.pass # let workers finish
|
30
29
|
|
31
30
|
# soft exit
|
32
|
-
|
33
|
-
|
31
|
+
join = lambda do |timeout|
|
32
|
+
start = Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
33
|
+
|
34
|
+
loop do
|
35
|
+
terminating_th = @threads.synchronize { @threads.first }
|
36
|
+
|
37
|
+
return unless terminating_th
|
38
|
+
|
39
|
+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
34
40
|
|
35
|
-
|
41
|
+
break if elapsed > timeout
|
42
|
+
|
43
|
+
terminating_th.join(timeout - elapsed)
|
44
|
+
end
|
36
45
|
end
|
37
46
|
|
47
|
+
join.call(shutdown_timeout)
|
48
|
+
|
38
49
|
# hard exit
|
39
|
-
@threads.each { |th| th.raise(KillError) }
|
40
|
-
|
41
|
-
|
42
|
-
|
50
|
+
@threads.synchronize { @threads.each { |th| th.raise(KillError) } }
|
51
|
+
join.call(grace_shutdown_timeout)
|
52
|
+
@threads.synchronize { @threads.each(&:kill) }
|
53
|
+
join.call(1)
|
43
54
|
end
|
44
55
|
|
45
56
|
private
|
@@ -63,8 +74,6 @@ module Tobox
|
|
63
74
|
subst_thread = start_thread_worker(subst_worker)
|
64
75
|
@threads << subst_thread
|
65
76
|
end
|
66
|
-
# all workers went down abruply, we need to kill the process.
|
67
|
-
# @parent_thread.raise(Interrupt) if wk.finished? && @threads.empty? && @running
|
68
77
|
end
|
69
78
|
end
|
70
79
|
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.5.
|
4
|
+
version: 0.5.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-09-
|
11
|
+
date: 2024-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|