resqued 0.10.0 → 0.11.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
- SHA1:
3
- metadata.gz: d56c813a2d3adf7d10fe76dafefff24c263f9766
4
- data.tar.gz: e3c9cd5fc92aca0b70d4d8ed31de6f15c418c94c
2
+ SHA256:
3
+ metadata.gz: 3b8956c8d1035f7289519c1bb7c136efa41fafde26f9caec7feb514b09270132
4
+ data.tar.gz: 05150d5f65763b0712b7d272cd44bc328b7a302042cc6fc98f5d34424aaca15d
5
5
  SHA512:
6
- metadata.gz: a28be514424a281b554224c78ba0d4fa6ff328f1d9fff622c76653c09ceefc6bc6c70cdb389d41dbd566fa202741d073ad6817103d2231237cbfdd726dd32473
7
- data.tar.gz: 14375d125a0c9e89ecc1918fa6d46f062206ddc0ac08a3ac8f504e7aeab563f90ea3d62cb54b955b1408f3308692b9cc98479c19d2d420b0136d73c10182687d
6
+ metadata.gz: 12b640ca8b2d567dffd82e19e150e984461ba42c7b143650162b31e8812c31c47b9a1813c9f54df72f1cd19ccd51f80fa8f71dcc74c5805e5453c3798f5707a2
7
+ data.tar.gz: 355f43fe2e0d2b6d91b440e9bd7a7cd921c5134b17d4e934a06cbe33e52c5feef99fd8b14e93706a6e78b3c2f04e1fbc98386eba711e550855a5c023b0c57d4e
data/CHANGES.md CHANGED
@@ -1,5 +1,26 @@
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.11.1
4
+ -------
5
+ * Fix a crash during shutdown. (#62)
6
+
7
+ v0.11.0
8
+ -------
9
+ * Ignore SIGHUP in Listener and Worker processes. (#61)
10
+
11
+ v0.10.3
12
+ -------
13
+ * Fix a timing related crash during reload. (#60)
14
+
15
+ v0.10.2
16
+ -------
17
+ * Shut down cleanly even if there are other stray child processes of the master. (#59)
18
+
19
+ v0.10.1
20
+ -------
21
+ * Avoid deadlock if a listener stops responding. (#58)
22
+ * When using 'percent' for a queue in a worker pool, always assign at least one worker. (#57)
23
+
3
24
  v0.10.0
4
25
  -------
5
26
  * Master process restarts itself (#51), so that it doesn't continue running stale code indefinitely. This will help with the rollout process when changes like #50 are introduced, so that the master process will catch up. The risk of this is that the master process might not be able to be restarted, which would lead to it crashing. The mostly likely way for that to happen is if you try to roll back your version of resqued to 0.9.0 or earlier. If you need to do that, ensure that your process monitor (systemd, god, etc.) is able to restart the master process. You can disable the new behavior by passing `--no-exec-on-hup`.
data/docs/signals.md CHANGED
@@ -34,6 +34,8 @@ The Listener process forwards `SIGCONT` to all of its workers.
34
34
 
35
35
  The Listener process handles `SIGINT`, `SIGTERM`, and `SIGQUIT`. When it receives one of these signals, it goes into shutdown mode. It sends the received signal to all of its workers. When all workers have exited, the Listener process exits.
36
36
 
37
+ The Listener process handles `SIGHUP` and does nothing. This makes it easier to reload resqued in a docker container, since many container platforms will send a requested signal to all processes in the container.
38
+
37
39
  ## Worker
38
40
 
39
41
  The Worker process uses resque's signal handling. Resque 1.23.0 handles the following signals:
@@ -44,3 +46,5 @@ The Worker process uses resque's signal handling. Resque 1.23.0 handles the foll
44
46
  * `USR1`: Kill the forked child immediately, continue processing jobs.
45
47
  * `USR2`: Don't process any new jobs
46
48
  * `CONT`: Start processing jobs again after a USR2
49
+
50
+ Resqued leaves a handler for `HUP` in place that does nothing. This makes it easier to reload resqued in a docker container, since many container platforms will send a requested signal to all processes in the container.
@@ -112,7 +112,7 @@ module Resqued
112
112
  elsif value.is_a?(1.class)
113
113
  value < @pool_size ? value : @pool_size
114
114
  elsif value.is_a?(Float) && value >= 0.0 && value <= 1.0
115
- (@pool_size * value).to_i
115
+ [(@pool_size * value).to_i, 1].max
116
116
  else
117
117
  raise TypeError, "Unknown concurrency value: #{value.inspect}"
118
118
  end
@@ -63,12 +63,13 @@ module Resqued
63
63
  end
64
64
 
65
65
  SIGNALS = [:CONT, :QUIT, :INT, :TERM].freeze
66
- ALL_SIGNALS = SIGNALS + [:CHLD]
66
+ ALL_SIGNALS = SIGNALS + [:CHLD, :HUP]
67
67
 
68
68
  SIGNAL_QUEUE = [] # rubocop: disable Style/MutableConstant
69
69
 
70
70
  # Public: Run the main loop.
71
71
  def run
72
+ trap(:HUP) {} # ignore this, in case it trickles in from the master.
72
73
  trap(:CHLD) { awake }
73
74
  SIGNALS.each { |signal| trap(signal) { SIGNAL_QUEUE << signal; awake } }
74
75
  @socket.close_on_exec = true
@@ -85,6 +86,8 @@ module Resqued
85
86
 
86
87
  write_procline("shutdown")
87
88
  burn_down_workers(exit_signal || :QUIT)
89
+ @socket&.close
90
+ @socket = nil
88
91
  end
89
92
 
90
93
  # Private.
@@ -25,6 +25,11 @@ module Resqued
25
25
  @listener_proxies.size
26
26
  end
27
27
 
28
+ # Public: Are the listeners all gone?
29
+ def empty?
30
+ @listener_proxies.empty?
31
+ end
32
+
28
33
  # Public: Initialize a new listener, run it, and record it as the current listener. Returns its ListenerProxy.
29
34
  def start!
30
35
  listener_state = ListenerState.new
@@ -99,7 +99,10 @@ module Resqued
99
99
  def worker_finished(pid)
100
100
  return if @state.master_socket.nil?
101
101
 
102
- @state.master_socket.puts(pid)
102
+ @state.master_socket.write_nonblock("#{pid}\n")
103
+ rescue IO::WaitWritable
104
+ log "Couldn't tell #{@state.pid} that #{pid} exited!"
105
+ # Ignore it, maybe the next time it'll work.
103
106
  rescue Errno::EPIPE
104
107
  @state.master_socket.close
105
108
  @state.master_socket = nil
@@ -187,7 +187,7 @@ module Resqued
187
187
  end
188
188
 
189
189
  def reap_all_listeners(waitpid_flags = 0)
190
- loop do
190
+ until @listeners.empty?
191
191
  begin
192
192
  lpid, status = Process.waitpid2(-1, waitpid_flags)
193
193
  return unless lpid
@@ -200,12 +200,14 @@ module Resqued
200
200
  end
201
201
 
202
202
  if @listeners.last_good_pid == lpid
203
- @state.clear_last_good!
203
+ @listeners.clear_last_good!
204
+ end
205
+
206
+ if dead_listener = @listeners.delete(lpid)
207
+ listener_status dead_listener, "stop"
208
+ dead_listener.dispose
204
209
  end
205
210
 
206
- dead_listener = @listeners.delete(lpid)
207
- listener_status dead_listener, "stop"
208
- dead_listener.dispose
209
211
  write_procline
210
212
  rescue Errno::ECHILD
211
213
  return
@@ -1,3 +1,3 @@
1
1
  module Resqued
2
- VERSION = "0.10.0".freeze
2
+ VERSION = "0.11.1".freeze
3
3
  end
@@ -91,7 +91,11 @@ module Resqued
91
91
  else
92
92
  # In case we get a signal before resque is ready for it.
93
93
  Resqued::Listener::ALL_SIGNALS.each { |signal| trap(signal, "DEFAULT") }
94
- trap(:QUIT) { exit! 0 } # If we get a QUIT during boot, just spin back down.
94
+ # Continue ignoring SIGHUP, though.
95
+ trap(:HUP) {}
96
+ # If we get a QUIT during boot, just spin back down.
97
+ trap(:QUIT) { exit! 0 }
98
+
95
99
  $0 = "STARTING RESQUE FOR #{queues.join(',')}"
96
100
  resque_worker = @worker_factory.call(queues)
97
101
  @config.after_fork(resque_worker)
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ describe "Listener still starting on SIGHUP" do
4
+ include ResquedIntegrationHelpers
5
+
6
+ it "expect master not to crash" do
7
+ start_resqued config: <<-CONFIG
8
+ before_fork do
9
+ sleep 1
10
+ end
11
+ CONFIG
12
+ expect_running listener: "listener #1"
13
+ restart_resqued
14
+ sleep 2
15
+ expect_running listener: "listener #2"
16
+ end
17
+
18
+ after do
19
+ begin
20
+ Process.kill(:QUIT, @pid) if @pid
21
+ rescue Errno::ESRCH
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,85 @@
1
+ require "spec_helper"
2
+ require "timeout"
3
+
4
+ describe "Resqued master with an extra child process" do
5
+ include ResquedPath
6
+
7
+ # Starts resqued with an extra child process.
8
+ def start_resqued_with_extra_child
9
+ shim_path = File.expand_path("../support/extra-child-shim", File.dirname(__FILE__))
10
+
11
+ config_path = File.join(SPEC_TEMPDIR, "config.rb")
12
+ File.write(config_path, <<-CONFIG)
13
+ before_fork { File.write(ENV["LISTENER_PIDFILE"], $$.to_s) }
14
+ CONFIG
15
+
16
+ logfile = File.join(SPEC_TEMPDIR, "resqued.log")
17
+ File.write(logfile, "") # truncate it
18
+
19
+ env = {
20
+ "LISTENER_PIDFILE" => listener_pidfile,
21
+ "EXTRA_CHILD_PIDFILE" => extra_child_pidfile,
22
+ }
23
+
24
+ pid = spawn(env, shim_path, resqued_path, "--logfile", logfile, config_path)
25
+ sleep 2.0
26
+ pid
27
+ end
28
+
29
+ let(:extra_child_pidfile) { File.join(SPEC_TEMPDIR, "extra-child.pid") }
30
+ def extra_child_pid
31
+ File.read(extra_child_pidfile).to_i
32
+ end
33
+
34
+ let(:listener_pidfile) { File.join(File.join(SPEC_TEMPDIR, "listener.pid")) }
35
+ def listener_pid
36
+ File.read(listener_pidfile).to_i
37
+ end
38
+
39
+ before do
40
+ File.unlink(extra_child_pidfile) rescue nil
41
+ File.unlink(listener_pidfile) rescue nil
42
+ @resqued_pid = start_resqued_with_extra_child
43
+ end
44
+
45
+ after do
46
+ kill_safely(:TERM) { @resqued_pid }
47
+ kill_safely(:KILL) { extra_child_pid }
48
+ sleep 0.1
49
+ kill_safely(:KILL) { @resqued_pid }
50
+ end
51
+
52
+ it "doesn't exit when listener dies unexpectedly" do
53
+ # Kill off the listener process.
54
+ first_listener_pid = listener_pid
55
+ Process.kill :QUIT, first_listener_pid
56
+ # Let Resqued::Backoff decide it's OK to start the listener again.
57
+ sleep 2.5
58
+ # Resqued should start a new listener to replace the dead one.
59
+ expect(listener_pid).not_to eq(first_listener_pid)
60
+ end
61
+
62
+ it "exits when listeners have all exited during shutdown" do
63
+ # Do a normal shutdown.
64
+ Process.kill :QUIT, @resqued_pid
65
+ # Expect the resqued process to exit.
66
+ expect(Timeout.timeout(5.0) { Process.waitpid(@resqued_pid) }).to eq(@resqued_pid)
67
+ end
68
+
69
+ it "doesn't crash when extra child exits" do
70
+ # Kill off the extra child process. Resqued should wait on it, but not exit.
71
+ Process.kill :KILL, extra_child_pid
72
+ sleep 1.0
73
+ # The resqued process should not have exited.
74
+ expect(Process.waitpid(@resqued_pid, Process::WNOHANG)).to be_nil
75
+ expect(Process.kill(0, @resqued_pid)).to eq(1)
76
+ end
77
+
78
+ def kill_safely(signal)
79
+ return unless pid = yield
80
+
81
+ Process.kill(signal, pid)
82
+ rescue Errno::ESRCH, Errno::ENOENT
83
+ # Process isn't there anymore, or pidfile isn't there. :+1:
84
+ end
85
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe "Resqued can restart" do
4
+ include ResquedIntegrationHelpers
5
+
6
+ it "expect to be able to restart" do
7
+ start_resqued
8
+ expect_running listener: "listener #1"
9
+ restart_resqued
10
+ expect_running listener: "listener #2"
11
+ stop_resqued
12
+ expect_not_running
13
+ end
14
+
15
+ after do
16
+ begin
17
+ Process.kill(:QUIT, @pid) if @pid
18
+ rescue Errno::ESRCH
19
+ end
20
+ end
21
+ end
@@ -6,7 +6,7 @@ describe Resqued::Backoff do
6
6
  let(:backoff) { described_class.new(min: 0.5, max: 64.0) }
7
7
 
8
8
  it "can start on the first try" do
9
- expect(backoff.wait?).to be_false
9
+ expect(backoff.wait?).to be_falsey
10
10
  end
11
11
 
12
12
  it "has no waiting at first" do
@@ -15,42 +15,42 @@ describe Resqued::Backoff do
15
15
 
16
16
  context "after expected exits" do
17
17
  before { 3.times { backoff.started } }
18
- it { expect(backoff.wait?).to be_true }
18
+ it { expect(backoff.wait?).to be true }
19
19
  it { expect(backoff.how_long?).to be_close_to(0.5) }
20
20
  end
21
21
 
22
22
  context "after one quick exit" do
23
23
  before { 1.times { backoff.started; backoff.died } }
24
- it { expect(backoff.wait?).to be_true }
24
+ it { expect(backoff.wait?).to be true }
25
25
  it { expect(backoff.how_long?).to be_close_to(1.0) }
26
26
  end
27
27
 
28
28
  context "after two quick starts" do
29
29
  before { 2.times { backoff.started; backoff.died } }
30
- it { expect(backoff.wait?).to be_true }
30
+ it { expect(backoff.wait?).to be true }
31
31
  it { expect(backoff.how_long?).to be_close_to(2.0) }
32
32
  end
33
33
 
34
34
  context "after five quick starts" do
35
35
  before { 6.times { backoff.started; backoff.died } }
36
- it { expect(backoff.wait?).to be_true }
36
+ it { expect(backoff.wait?).to be true }
37
37
  it { expect(backoff.how_long?).to be_close_to(32.0) }
38
38
  end
39
39
 
40
40
  context "after six quick starts" do
41
41
  before { 7.times { backoff.started; backoff.died } }
42
- it { expect(backoff.wait?).to be_true }
42
+ it { expect(backoff.wait?).to be true }
43
43
  it { expect(backoff.how_long?).to be_close_to(64.0) }
44
44
  end
45
45
 
46
46
  context "does not wait longer than 64s" do
47
47
  before { 8.times { backoff.started; backoff.died } }
48
- it { expect(backoff.wait?).to be_true }
48
+ it { expect(backoff.wait?).to be true }
49
49
  it { expect(backoff.how_long?).to be_close_to(64.0) }
50
50
  it "and resets after an expected exit" do
51
51
  backoff.started
52
52
  backoff.started
53
- expect(backoff.wait?).to be_true
53
+ expect(backoff.wait?).to be true
54
54
  expect(backoff.how_long?).to be_close_to(0.5)
55
55
  end
56
56
  end
@@ -55,6 +55,17 @@ describe Resqued::Config::Worker do
55
55
  end
56
56
  end
57
57
 
58
+ context "small pool with percent" do
59
+ let(:config) { <<-END_CONFIG }
60
+ worker_pool 2
61
+ queue "a"
62
+ queue "b", :percent => 45
63
+ END_CONFIG
64
+ it { expect(result.size).to eq(2) }
65
+ it { expect(result[0]).to eq(queues: ["a", "b"]) }
66
+ it { expect(result[1]).to eq(queues: ["a"]) }
67
+ end
68
+
58
69
  context "pool (hash for concurrency)" do
59
70
  let(:config) { <<-END_CONFIG }
60
71
  before_fork { }
@@ -114,17 +125,17 @@ describe Resqued::Config::Worker do
114
125
 
115
126
  context "pool, with shuffled queues" do
116
127
  let(:config) { <<-END_CONFIG }
117
- worker_pool 20, :shuffle_queues => true
118
- queue 'a', :count => 10
119
- queue 'b', :count => 15
128
+ worker_pool 200, :shuffle_queues => true
129
+ queue 'a', :count => 100
130
+ queue 'b', :count => 150
120
131
  END_CONFIG
121
- it { expect(result.size).to eq(20) }
122
- it { (0..9).each { |i| expect(result[i][:queues].sort).to eq(["a", "b"]) } }
123
- it { (10..14).each { |i| expect(result[i][:queues]).to eq(["b"]) } }
124
- it { (15..19).each { |i| expect(result[i][:queues]).to eq(["*"]) } }
132
+ it { expect(result.size).to eq(200) }
133
+ it { (0..99).each { |i| expect(result[i][:queues].sort).to eq(["a", "b"]) } }
134
+ it { (100..149).each { |i| expect(result[i][:queues]).to eq(["b"]) } }
135
+ it { (150..199).each { |i| expect(result[i][:queues]).to eq(["*"]) } }
125
136
  it { result.each { |x| expect(x).not_to have_key(:shuffle_queues) } }
126
137
  it do
127
- shuffled_queues = result.take(10).map { |x| x[:queues] }
138
+ shuffled_queues = result.take(100).map { |x| x[:queues] }
128
139
  expect(shuffled_queues.sort.uniq).to eq([["a", "b"], ["b", "a"]]) # Some of the queues should be shuffled
129
140
  end
130
141
  end
@@ -7,8 +7,8 @@ describe Resqued::TestCase do
7
7
  context "LoadConfig" do
8
8
  let(:the_module) { described_class::LoadConfig }
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
- it { expect { test_case.assert_resqued "spec/fixtures/test_case_environment.rb", "spec/fixtures/test_case_before_fork_raises.rb" }.to raise_error }
11
- it { expect { test_case.assert_resqued "spec/fixtures/test_case_environment.rb", "spec/fixtures/test_case_after_fork_raises.rb" }.to raise_error }
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
+ 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
12
  it { expect { test_case.assert_resqued "spec/fixtures/test_case_environment.rb", "spec/fixtures/test_case_no_workers.rb" }.not_to raise_error }
13
13
  end
14
14
  end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,6 @@
1
1
  require "support/custom_matchers"
2
+ require "support/resqued_path"
3
+ require "support/resqued_integration_helpers"
4
+
5
+ SPEC_TEMPDIR = File.expand_path("../tmp/spec", File.dirname(__FILE__))
6
+ FileUtils.mkpath(SPEC_TEMPDIR)
@@ -11,6 +11,10 @@ module CustomMatchers
11
11
  @epsilon = 0.01
12
12
  end
13
13
 
14
+ def supports_block_expectations?
15
+ true
16
+ end
17
+
14
18
  def within(epsilon)
15
19
  @epsilon = epsilon
16
20
  self
@@ -24,9 +28,13 @@ module CustomMatchers
24
28
  @epsilon >= diff
25
29
  end
26
30
 
27
- def failure_message_for_should
31
+ def failure_message
28
32
  "Expected block to run for #{@expected_duration} +/-#{@epsilon} seconds, but it ran for #{@actual_duration} seconds."
29
33
  end
34
+
35
+ def failure_message_when_negated
36
+ "Expected block not to run for #{@expected_duration} +/-#{@epsilon} seconds, but it ran for #{@actual_duration} seconds."
37
+ end
30
38
  end
31
39
  end
32
40
 
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ extra_child_pid = fork { sleep(100); exit! }
4
+ File.write(ENV["EXTRA_CHILD_PIDFILE"], extra_child_pid.to_s)
5
+
6
+ exec(*ARGV)
@@ -0,0 +1,50 @@
1
+ module ResquedIntegrationHelpers
2
+ include ResquedPath
3
+
4
+ def start_resqued(config: "", debug: false)
5
+ # Don't configure any workers. That way, we don't need to have redis running.
6
+ config_path = File.join(SPEC_TEMPDIR, "config.rb")
7
+ File.write(config_path, config)
8
+
9
+ @pid =
10
+ if debug
11
+ spawn resqued_path, config_path
12
+ else
13
+ logfile = File.join(SPEC_TEMPDIR, "resqued.log")
14
+ File.write(logfile, "") # truncate it
15
+
16
+ spawn resqued_path, "--logfile", logfile, config_path
17
+ end
18
+ sleep 1.0
19
+ end
20
+
21
+ def restart_resqued
22
+ Process.kill(:HUP, @pid)
23
+ sleep 1.0
24
+ end
25
+
26
+ def expect_running(listener:)
27
+ processes = list_processes
28
+ expect(processes).to include(is_resqued_master)
29
+ listeners = processes.select { |p| p[:ppid] == @pid }.map { |p| p[:args] }
30
+ expect(listeners).to all(match(/#{listener}/)).and(satisfy { |l| l.size == 1 })
31
+ end
32
+
33
+ def expect_not_running
34
+ processes = list_processes
35
+ expect(processes).not_to include(is_resqued_master)
36
+ end
37
+
38
+ def stop_resqued
39
+ Process.kill(:TERM, @pid)
40
+ sleep 1.0
41
+ end
42
+
43
+ def list_processes
44
+ `ps axo pid,ppid,args`.lines.map { |line| pid, ppid, args = line.strip.split(/\s+/, 3); { pid: pid.to_i, ppid: ppid.to_i, args: args } }
45
+ end
46
+
47
+ def is_resqued_master
48
+ satisfy { |p| p[:pid] == @pid && p[:args] =~ /resqued-/ }
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+ module ResquedPath
2
+ def resqued_path
3
+ return @resqued_path if @resqued_path
4
+
5
+ @resqued_path = File.expand_path("../../gemfiles/bin/resqued", File.dirname(__FILE__))
6
+ unless File.executable?(@resqued_path)
7
+ @resqued_path = File.expand_path("../../bin/resqued", File.dirname(__FILE__))
8
+ end
9
+ @resqued_path
10
+ end
11
+ end
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.10.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Burke
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-30 00:00:00.000000000 Z
11
+ date: 2021-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kgio
@@ -56,36 +56,30 @@ dependencies:
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 0.9.0
61
+ version: 13.0.1
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 0.9.0
68
+ version: 13.0.1
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '2.0'
76
- - - "<"
73
+ - - '='
77
74
  - !ruby/object:Gem::Version
78
- version: '2.99'
75
+ version: 3.9.0
79
76
  type: :development
80
77
  prerelease: false
81
78
  version_requirements: !ruby/object:Gem::Requirement
82
79
  requirements:
83
- - - "~>"
84
- - !ruby/object:Gem::Version
85
- version: '2.0'
86
- - - "<"
80
+ - - '='
87
81
  - !ruby/object:Gem::Version
88
- version: '2.99'
82
+ version: 3.9.0
89
83
  - !ruby/object:Gem::Dependency
90
84
  name: rubocop
91
85
  requirement: !ruby/object:Gem::Requirement
@@ -143,6 +137,9 @@ files:
143
137
  - spec/fixtures/test_case_clean.rb
144
138
  - spec/fixtures/test_case_environment.rb
145
139
  - spec/fixtures/test_case_no_workers.rb
140
+ - spec/integration/listener_still_starting_spec.rb
141
+ - spec/integration/master_inherits_child_spec.rb
142
+ - spec/integration/restart_spec.rb
146
143
  - spec/resqued/backoff_spec.rb
147
144
  - spec/resqued/config/fork_event_spec.rb
148
145
  - spec/resqued/config/worker_spec.rb
@@ -152,7 +149,9 @@ files:
152
149
  - spec/resqued/test_case_spec.rb
153
150
  - spec/spec_helper.rb
154
151
  - spec/support/custom_matchers.rb
155
- - spec/test_restart.sh
152
+ - spec/support/extra-child-shim
153
+ - spec/support/resqued_integration_helpers.rb
154
+ - spec/support/resqued_path.rb
156
155
  homepage: https://github.com/spraints/resqued
157
156
  licenses:
158
157
  - MIT
@@ -172,24 +171,28 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
171
  - !ruby/object:Gem::Version
173
172
  version: '0'
174
173
  requirements: []
175
- rubyforge_project:
176
- rubygems_version: 2.5.2.1
174
+ rubygems_version: 3.0.3
177
175
  signing_key:
178
176
  specification_version: 4
179
177
  summary: Daemon of resque workers
180
178
  test_files:
181
- - spec/resqued/sleepy_spec.rb
182
- - spec/resqued/backoff_spec.rb
183
- - spec/resqued/config/worker_spec.rb
184
- - spec/resqued/config/fork_event_spec.rb
185
- - spec/resqued/start_ctx_spec.rb
186
- - spec/resqued/config_spec.rb
187
- - spec/resqued/test_case_spec.rb
188
179
  - spec/spec_helper.rb
180
+ - spec/integration/restart_spec.rb
181
+ - spec/integration/listener_still_starting_spec.rb
182
+ - spec/integration/master_inherits_child_spec.rb
183
+ - spec/support/resqued_integration_helpers.rb
184
+ - spec/support/custom_matchers.rb
185
+ - spec/support/resqued_path.rb
186
+ - spec/support/extra-child-shim
187
+ - spec/fixtures/test_case_clean.rb
189
188
  - spec/fixtures/test_case_before_fork_raises.rb
190
189
  - spec/fixtures/test_case_environment.rb
191
190
  - spec/fixtures/test_case_no_workers.rb
192
191
  - spec/fixtures/test_case_after_fork_raises.rb
193
- - spec/fixtures/test_case_clean.rb
194
- - spec/test_restart.sh
195
- - spec/support/custom_matchers.rb
192
+ - spec/resqued/config_spec.rb
193
+ - spec/resqued/config/fork_event_spec.rb
194
+ - spec/resqued/config/worker_spec.rb
195
+ - spec/resqued/sleepy_spec.rb
196
+ - spec/resqued/test_case_spec.rb
197
+ - spec/resqued/start_ctx_spec.rb
198
+ - spec/resqued/backoff_spec.rb
data/spec/test_restart.sh DELETED
@@ -1,84 +0,0 @@
1
- #!/bin/bash
2
-
3
- set -e
4
- set -o nounset
5
-
6
- WORKDIR="$(mktemp)"
7
- PIDFILE="${WORKDIR}/resqued.pid"
8
- CONFIG="${WORKDIR}/config.rb"
9
-
10
- # mktemp makes a file, but we want a dir.
11
- rm -f "$WORKDIR"
12
- mkdir "$WORKDIR"
13
-
14
- set -x
15
- cd "$(dirname "$0")/.."
16
-
17
- main() {
18
- trap cleanup EXIT
19
-
20
- configure_resqued
21
- start_resqued
22
- restart_resqued
23
- stop_resqued
24
- }
25
-
26
- configure_resqued() {
27
- # Don't configure any workers. That way, we don't need to have redis running.
28
- touch "${CONFIG}"
29
- }
30
-
31
- start_resqued() {
32
- bin_resqued=bin/resqued
33
- if [ -x gemfiles/bin/resqued ]; then
34
- bin_resqued=gemfiles/bin/resqued
35
- fi
36
- $bin_resqued --pidfile "${PIDFILE}" "${CONFIG}" &
37
- sleep 1
38
- echo expect to find the master process and the first listener
39
- running # set -e will make the test fail if it's not running
40
- ps axo pid,args -H | grep [r]esqued-
41
- ps axo pid,args | grep [r]esqued- | grep -q 'listener #1.*running'
42
- }
43
-
44
- restart_resqued() {
45
- local pid="$(cat "${PIDFILE}")"
46
- kill -HUP "$pid"
47
- sleep 1
48
- echo expect to find the master process and the second listener
49
- running
50
- ps axo pid,args -H | grep [r]esqued-
51
- ps axo pid,args | grep [r]esqued- | grep -qv 'listener #1'
52
- ps axo pid,args | grep [r]esqued- | grep -q 'listener #2.*running'
53
- }
54
-
55
- stop_resqued() {
56
- local pid="$(cat "${PIDFILE}")"
57
- kill -TERM "$pid"
58
- sleep 1
59
- echo expect everything to be stopped
60
- if running >&/dev/null; then
61
- echo "expected resqued to be stopped"
62
- false
63
- fi
64
- ps axo pid,args -H | grep [r]esqued- || true
65
- test -z "$(ps axo pid,args | grep [r]esqued-)"
66
- }
67
-
68
- running() {
69
- set -e
70
- test -f "${PIDFILE}"
71
- local pid="$(cat "${PIDFILE}")"
72
- kill -0 "$pid"
73
- ps o pid,args "$pid"
74
- }
75
-
76
- cleanup() {
77
- while running >&/dev/null; do
78
- kill -TERM "$(cat "${PIDFILE}")"
79
- sleep 2
80
- done
81
- rm -rfv "${WORKDIR}" || rm -rf "${WORKDIR}"
82
- }
83
-
84
- main