resqued 0.12.1 → 0.12.3
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/CHANGES.md +8 -0
- data/README.md +5 -0
- data/exe/resqued +6 -1
- data/lib/resqued/config/after_exit.rb +22 -0
- data/lib/resqued/config/dsl.rb +4 -0
- data/lib/resqued/config.rb +6 -0
- data/lib/resqued/quit-and-wait.rb +84 -0
- data/lib/resqued/test_case.rb +1 -0
- data/lib/resqued/version.rb +1 -1
- data/lib/resqued/worker.rb +15 -0
- data/spec/fixtures/test_case_after_exit_raises.rb +5 -0
- data/spec/integration/quit_and_wait_spec.rb +37 -0
- data/spec/resqued/config/exit_event_spec.rb +47 -0
- data/spec/resqued/test_case_spec.rb +1 -0
- data/spec/support/resqued_integration_helpers.rb +15 -10
- metadata +27 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a05ff83ea7efb498899c8e366977f9b59e854c5c999ae9b8edcdb66e36ec8551
|
4
|
+
data.tar.gz: af4beac8bbd7b030527dc23b60587672126227a022560962f4d31f62efef5d5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55b640e571730cdaa8155c8296c21923eb54d9cb4fe93ec5245ee739e78201ff45736653544c070c0c6d012a0d83678d1158fe0243b1cf665d7292c29af10de6
|
7
|
+
data.tar.gz: b086650c78f7710ec143ac6e787a2cfd7809bae17c10fc9583259a37ae258ef65df3252052d6c5d35309e5c2ae15a90180fa856803bae40f356c277f6628d3fb
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
Starting with version 0.6.1, resqued uses semantic versioning to indicate incompatibilities between the master process, listener process, and configuration.
|
2
2
|
|
3
|
+
v0.12.3
|
4
|
+
-------
|
5
|
+
* Add `after_exit` that provides a `WorkerSummary` about each exited worker.
|
6
|
+
|
7
|
+
v0.12.2
|
8
|
+
-------
|
9
|
+
* Added lifecycle hook for container runtimes. (#67)
|
10
|
+
|
3
11
|
v0.12.1
|
4
12
|
-------
|
5
13
|
* Fixed Resqued::TestCase. v0.12.0 introduced a regression that stopped
|
data/README.md
CHANGED
@@ -152,6 +152,11 @@ You can configure the Resque worker in the `after_fork` block
|
|
152
152
|
worker.term_timeout = 1.minute
|
153
153
|
end
|
154
154
|
|
155
|
+
after_exit do |worker_summary|
|
156
|
+
puts "Worker was alive for #{worker_summary.alive_time_sec}"
|
157
|
+
puts "Process::Status of exited worker: #{worker_summary.process_status.inspect}"
|
158
|
+
end
|
159
|
+
|
155
160
|
In this example, a Rails application is being set up with 7 workers:
|
156
161
|
* high
|
157
162
|
* low (interval = 30)
|
data/exe/resqued
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
case ARGV[0]
|
4
|
+
when "listener"
|
4
5
|
require "resqued/listener"
|
5
6
|
Resqued::Listener.exec!
|
6
7
|
exit 0
|
8
|
+
when "quit-and-wait"
|
9
|
+
require "resqued/quit-and-wait"
|
10
|
+
Resqued::QuitAndWait.exec!(ARGV.drop(1))
|
11
|
+
exit 0
|
7
12
|
end
|
8
13
|
|
9
14
|
require "optparse"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "resqued/config/base"
|
2
|
+
|
3
|
+
module Resqued
|
4
|
+
module Config
|
5
|
+
# A config handler that executes the `after_exit` block.
|
6
|
+
#
|
7
|
+
# after_exit do |worker_summary|
|
8
|
+
# # Runs in each listener.
|
9
|
+
# end
|
10
|
+
class AfterExit < Base
|
11
|
+
# Public.
|
12
|
+
def initialize(options = {})
|
13
|
+
@worker_summary = options.fetch(:worker_summary)
|
14
|
+
end
|
15
|
+
|
16
|
+
# DSL: execute the `after_exit` block.
|
17
|
+
def after_exit
|
18
|
+
yield @worker_summary
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/resqued/config/dsl.rb
CHANGED
data/lib/resqued/config.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "resqued/config/after_fork"
|
2
2
|
require "resqued/config/before_fork"
|
3
|
+
require "resqued/config/after_exit"
|
3
4
|
require "resqued/config/worker"
|
4
5
|
|
5
6
|
module Resqued
|
@@ -27,6 +28,11 @@ module Resqued
|
|
27
28
|
Resqued::Config::AfterFork.new(worker: worker).apply_all(@config_data)
|
28
29
|
end
|
29
30
|
|
31
|
+
# Public: Perform the `after_exit` action from the config.
|
32
|
+
def after_exit(worker_summary)
|
33
|
+
Resqued::Config::AfterExit.new(worker_summary: worker_summary).apply_all(@config_data)
|
34
|
+
end
|
35
|
+
|
30
36
|
# Public: Builds the workers specified in the config.
|
31
37
|
def build_workers
|
32
38
|
Resqued::Config::Worker.new(config: self).apply_all(@config_data)
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module Resqued
|
4
|
+
class QuitAndWait
|
5
|
+
def self.exec!(argv)
|
6
|
+
options = { grace_seconds: 30 }
|
7
|
+
|
8
|
+
opts = OptionParser.new do |opts| # rubocop: disable Lint/ShadowingOuterLocalVariable
|
9
|
+
opts.banner = <<~USAGE
|
10
|
+
Usage: resqued quit-and-wait PIDFILE [--grace-period SECONDS]
|
11
|
+
|
12
|
+
Use this as a preStop script in kubernetes. This script will send a SIGQUIT to
|
13
|
+
resqued immediately, and then sleep until either resqued exits or until the
|
14
|
+
grace period is nearing expiration. This script exits 0 if resqued exited and
|
15
|
+
99 otherwise.
|
16
|
+
USAGE
|
17
|
+
|
18
|
+
opts.on "-h", "--help", "Show this message" do
|
19
|
+
puts opts
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on "-v", "--version", "Show the version" do
|
24
|
+
require "resqued/version"
|
25
|
+
puts Resqued::VERSION
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on "--grace-period SECONDS", Numeric, "Grace period provided to container runtime (default 30)" do |v|
|
30
|
+
options[:grace_seconds] = v
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on "--quiet" do
|
34
|
+
options[:quiet] = true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
argv = opts.parse(argv)
|
39
|
+
if argv.size != 1
|
40
|
+
puts opts
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
options[:pidfile] = argv.shift
|
44
|
+
|
45
|
+
new(**options).exec!
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(grace_seconds:, pidfile:, quiet: false)
|
49
|
+
@grace_seconds = grace_seconds
|
50
|
+
@pidfile = pidfile
|
51
|
+
@quiet = quiet
|
52
|
+
end
|
53
|
+
|
54
|
+
attr_reader :grace_seconds, :pidfile, :quiet
|
55
|
+
|
56
|
+
def exec!
|
57
|
+
start = Time.now
|
58
|
+
stop_at = start + grace_seconds - 5
|
59
|
+
pid = File.read(pidfile).to_i
|
60
|
+
|
61
|
+
log "kill -QUIT #{pid} (resqued-master)"
|
62
|
+
Process.kill(:QUIT, pid)
|
63
|
+
|
64
|
+
while Time.now < stop_at
|
65
|
+
begin
|
66
|
+
# check if pid is still alive.
|
67
|
+
Process.kill(0, pid)
|
68
|
+
rescue Errno::ESRCH # no such process, it exited!
|
69
|
+
log "ok: resqued-master with pid #{pid} exited"
|
70
|
+
exit 0
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
log "giving up, resqued-master with pid #{pid} is still running."
|
75
|
+
exit 99
|
76
|
+
end
|
77
|
+
|
78
|
+
def log(message)
|
79
|
+
return if quiet
|
80
|
+
|
81
|
+
puts "#{Time.now.strftime('%H:%M:%S.%L')} #{message}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/resqued/test_case.rb
CHANGED
data/lib/resqued/version.rb
CHANGED
data/lib/resqued/worker.rb
CHANGED
@@ -64,6 +64,9 @@ module Resqued
|
|
64
64
|
@pid = nil
|
65
65
|
@backoff.died unless @killed
|
66
66
|
elsif !process_status.nil? && @self_started
|
67
|
+
alive_time_sec = Process.clock_gettime(Process::CLOCK_MONOTONIC) - @start_time
|
68
|
+
@config.after_exit(WorkerSummary.new(alive_time_sec: alive_time_sec, process_status: process_status))
|
69
|
+
|
67
70
|
log :debug, "#{summary} I exited: #{process_status}"
|
68
71
|
@pid = nil
|
69
72
|
@backoff.died unless @killed
|
@@ -84,6 +87,8 @@ module Resqued
|
|
84
87
|
@backoff.started
|
85
88
|
@self_started = true
|
86
89
|
@killed = false
|
90
|
+
@start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
91
|
+
|
87
92
|
if @pid = fork
|
88
93
|
@pids << @pid
|
89
94
|
# still in the listener
|
@@ -112,4 +117,14 @@ module Resqued
|
|
112
117
|
log "Can't kill #{pid}: #{e}"
|
113
118
|
end
|
114
119
|
end
|
120
|
+
|
121
|
+
# Metadata for an exited listener worker.
|
122
|
+
class WorkerSummary
|
123
|
+
attr_reader :alive_time_sec, :process_status
|
124
|
+
|
125
|
+
def initialize(alive_time_sec:, process_status:)
|
126
|
+
@alive_time_sec = alive_time_sec
|
127
|
+
@process_status = process_status
|
128
|
+
end
|
129
|
+
end
|
115
130
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "timeout"
|
3
|
+
|
4
|
+
describe "quit-and-wait gracefully stops resqued" do
|
5
|
+
include ResquedIntegrationHelpers
|
6
|
+
|
7
|
+
it do
|
8
|
+
pidfile = File.join(SPEC_TEMPDIR, "graceful.pid")
|
9
|
+
|
10
|
+
start_resqued(pidfile: pidfile)
|
11
|
+
expect_running listener: "listener #1"
|
12
|
+
|
13
|
+
# Make sure the process gets cleaned up.
|
14
|
+
Thread.new do
|
15
|
+
begin
|
16
|
+
loop do
|
17
|
+
Process.wait(@pid)
|
18
|
+
end
|
19
|
+
rescue Errno::ECHILD
|
20
|
+
# ok!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Timeout.timeout(15) do
|
25
|
+
expect(system(resqued_path, "quit-and-wait", pidfile, "--grace-period", "10")).to be true
|
26
|
+
end
|
27
|
+
|
28
|
+
expect_not_running
|
29
|
+
end
|
30
|
+
|
31
|
+
after do
|
32
|
+
begin
|
33
|
+
Process.kill(:QUIT, @pid) if @pid
|
34
|
+
rescue Errno::ESRCH
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "resqued/worker"
|
3
|
+
require "resqued/config/after_exit"
|
4
|
+
|
5
|
+
describe do
|
6
|
+
before { evaluator.apply(config) }
|
7
|
+
|
8
|
+
context "after_exit" do
|
9
|
+
# Run the after_exit block.
|
10
|
+
#
|
11
|
+
# after_exit do |worker_summary|
|
12
|
+
# puts "#{worker_summary.alive_time_sec}"
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# ignore calls to any other top-level method.
|
16
|
+
|
17
|
+
let(:config) { <<-END_CONFIG }
|
18
|
+
worker('one')
|
19
|
+
worker_pool(1)
|
20
|
+
queue('*')
|
21
|
+
|
22
|
+
after_exit do |worker_summary|
|
23
|
+
$after_exit_called = true
|
24
|
+
$worker_alive_time_sec = worker_summary.alive_time_sec
|
25
|
+
$exit_status = worker_summary.process_status.exitstatus
|
26
|
+
end
|
27
|
+
END_CONFIG
|
28
|
+
|
29
|
+
let(:evaluator) {
|
30
|
+
# In ruby versions < 3, Process::Status evaluates $? regardless of what status is returned by
|
31
|
+
# exitcode for a status created with Process::Status.allocate
|
32
|
+
fork do
|
33
|
+
exit!
|
34
|
+
end
|
35
|
+
_, status = Process.waitpid2
|
36
|
+
Resqued::Config::AfterExit.new(worker_summary: Resqued::WorkerSummary.new(alive_time_sec: 1, process_status: status))
|
37
|
+
}
|
38
|
+
|
39
|
+
it { expect($after_exit_called).to eq(true) }
|
40
|
+
it { expect($worker_alive_time_sec > 0).to eq(true) }
|
41
|
+
it { expect($exit_status).to eq(0) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class FakeResqueWorker
|
46
|
+
attr_accessor :token
|
47
|
+
end
|
@@ -9,6 +9,7 @@ describe Resqued::TestCase do
|
|
9
9
|
it { expect { test_case.assert_resqued "spec/fixtures/test_case_environment.rb", "spec/fixtures/test_case_clean.rb" }.not_to raise_error }
|
10
10
|
it { expect { test_case.assert_resqued "spec/fixtures/test_case_environment.rb", "spec/fixtures/test_case_before_fork_raises.rb" }.to raise_error(RuntimeError) }
|
11
11
|
it { expect { test_case.assert_resqued "spec/fixtures/test_case_environment.rb", "spec/fixtures/test_case_after_fork_raises.rb" }.to raise_error(RuntimeError) }
|
12
|
+
it { expect { test_case.assert_resqued "spec/fixtures/test_case_environment.rb", "spec/fixtures/test_case_after_exit_raises.rb" }.to raise_error(RuntimeError) }
|
12
13
|
it { expect { test_case.assert_resqued "spec/fixtures/test_case_environment.rb", "spec/fixtures/test_case_no_workers.rb" }.not_to raise_error }
|
13
14
|
end
|
14
15
|
end
|
@@ -1,20 +1,25 @@
|
|
1
1
|
module ResquedIntegrationHelpers
|
2
2
|
include ResquedPath
|
3
3
|
|
4
|
-
def start_resqued(config: "", debug: false)
|
5
|
-
# Don't configure any workers. That way, we don't need to have
|
4
|
+
def start_resqued(config: "", debug: false, pidfile: nil)
|
5
|
+
# Don't configure any workers by default. That way, we don't need to have
|
6
|
+
# redis running.
|
6
7
|
config_path = File.join(SPEC_TEMPDIR, "config.rb")
|
7
8
|
File.write(config_path, config)
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
cmd = [resqued_path]
|
11
|
+
if pidfile
|
12
|
+
cmd += ["--pidfile", pidfile]
|
13
|
+
end
|
14
|
+
unless debug
|
15
|
+
logfile = File.join(SPEC_TEMPDIR, "resqued.log")
|
16
|
+
File.write(logfile, "") # truncate it
|
17
|
+
cmd += ["--logfile", logfile]
|
18
|
+
end
|
19
|
+
cmd += [config_path]
|
20
|
+
|
21
|
+
@pid = spawn(*cmd)
|
15
22
|
|
16
|
-
spawn resqued_path, "--logfile", logfile, config_path
|
17
|
-
end
|
18
23
|
sleep 1.0
|
19
24
|
end
|
20
25
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resqued
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Burke
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kgio
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/resqued.rb
|
112
112
|
- lib/resqued/backoff.rb
|
113
113
|
- lib/resqued/config.rb
|
114
|
+
- lib/resqued/config/after_exit.rb
|
114
115
|
- lib/resqued/config/after_fork.rb
|
115
116
|
- lib/resqued/config/base.rb
|
116
117
|
- lib/resqued/config/before_fork.rb
|
@@ -127,11 +128,13 @@ files:
|
|
127
128
|
- lib/resqued/master_state.rb
|
128
129
|
- lib/resqued/pidfile.rb
|
129
130
|
- lib/resqued/procline_version.rb
|
131
|
+
- lib/resqued/quit-and-wait.rb
|
130
132
|
- lib/resqued/runtime_info.rb
|
131
133
|
- lib/resqued/sleepy.rb
|
132
134
|
- lib/resqued/test_case.rb
|
133
135
|
- lib/resqued/version.rb
|
134
136
|
- lib/resqued/worker.rb
|
137
|
+
- spec/fixtures/test_case_after_exit_raises.rb
|
135
138
|
- spec/fixtures/test_case_after_fork_raises.rb
|
136
139
|
- spec/fixtures/test_case_before_fork_raises.rb
|
137
140
|
- spec/fixtures/test_case_clean.rb
|
@@ -139,8 +142,10 @@ files:
|
|
139
142
|
- spec/fixtures/test_case_no_workers.rb
|
140
143
|
- spec/integration/listener_still_starting_spec.rb
|
141
144
|
- spec/integration/master_inherits_child_spec.rb
|
145
|
+
- spec/integration/quit_and_wait_spec.rb
|
142
146
|
- spec/integration/restart_spec.rb
|
143
147
|
- spec/resqued/backoff_spec.rb
|
148
|
+
- spec/resqued/config/exit_event_spec.rb
|
144
149
|
- spec/resqued/config/fork_event_spec.rb
|
145
150
|
- spec/resqued/config/worker_spec.rb
|
146
151
|
- spec/resqued/config_spec.rb
|
@@ -156,7 +161,7 @@ homepage: https://github.com/spraints/resqued
|
|
156
161
|
licenses:
|
157
162
|
- MIT
|
158
163
|
metadata: {}
|
159
|
-
post_install_message:
|
164
|
+
post_install_message:
|
160
165
|
rdoc_options: []
|
161
166
|
require_paths:
|
162
167
|
- lib
|
@@ -171,28 +176,31 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
176
|
- !ruby/object:Gem::Version
|
172
177
|
version: '0'
|
173
178
|
requirements: []
|
174
|
-
rubygems_version: 3.
|
175
|
-
signing_key:
|
179
|
+
rubygems_version: 3.1.6
|
180
|
+
signing_key:
|
176
181
|
specification_version: 4
|
177
182
|
summary: Daemon of resque workers
|
178
183
|
test_files:
|
179
|
-
- spec/
|
180
|
-
- spec/
|
184
|
+
- spec/spec_helper.rb
|
185
|
+
- spec/integration/restart_spec.rb
|
186
|
+
- spec/integration/quit_and_wait_spec.rb
|
187
|
+
- spec/integration/listener_still_starting_spec.rb
|
188
|
+
- spec/integration/master_inherits_child_spec.rb
|
189
|
+
- spec/support/resqued_integration_helpers.rb
|
190
|
+
- spec/support/custom_matchers.rb
|
191
|
+
- spec/support/resqued_path.rb
|
192
|
+
- spec/support/extra-child-shim
|
181
193
|
- spec/fixtures/test_case_clean.rb
|
194
|
+
- spec/fixtures/test_case_before_fork_raises.rb
|
182
195
|
- spec/fixtures/test_case_environment.rb
|
183
196
|
- spec/fixtures/test_case_no_workers.rb
|
184
|
-
- spec/
|
185
|
-
- spec/
|
186
|
-
- spec/
|
187
|
-
- spec/resqued/backoff_spec.rb
|
197
|
+
- spec/fixtures/test_case_after_fork_raises.rb
|
198
|
+
- spec/fixtures/test_case_after_exit_raises.rb
|
199
|
+
- spec/resqued/config_spec.rb
|
188
200
|
- spec/resqued/config/fork_event_spec.rb
|
189
201
|
- spec/resqued/config/worker_spec.rb
|
190
|
-
- spec/resqued/
|
202
|
+
- spec/resqued/config/exit_event_spec.rb
|
191
203
|
- spec/resqued/sleepy_spec.rb
|
192
|
-
- spec/resqued/start_ctx_spec.rb
|
193
204
|
- spec/resqued/test_case_spec.rb
|
194
|
-
- spec/
|
195
|
-
- spec/
|
196
|
-
- spec/support/extra-child-shim
|
197
|
-
- spec/support/resqued_integration_helpers.rb
|
198
|
-
- spec/support/resqued_path.rb
|
205
|
+
- spec/resqued/start_ctx_spec.rb
|
206
|
+
- spec/resqued/backoff_spec.rb
|