sidekiq-process_manager 1.1.0 → 1.1.2

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: d03e818fac3487ed18d2763f536b2e97fa526b8d7dd066b1a066407727ff0dba
4
- data.tar.gz: 1e3e1837c3367a22ced37e111ad6e7d1e9988bcdd7baaf1d07b0b3083857650e
3
+ metadata.gz: dc25ffae388e5ca7ad73f0976d00cf09ec84124b2284a000af1dc0970cf87c20
4
+ data.tar.gz: 94637ae3cfa8a6fa991e95ee434c8410936c62263695f36b6db8c2b664d1f439
5
5
  SHA512:
6
- metadata.gz: feae2e03df3bc77c6590a1da6bcb5079761184a6e5d37f05c81451b7f52783c8b496dbbdfa71b793a8adfe7eaf8bde293e185ec1ecc1b0a90a802cab772a30dc
7
- data.tar.gz: 988f0f484e747142c8b725e80717bc0edefee68d9600595352f27a2c343535bc2c6e56ecde5c10dccf56c775b1210f9e50f3a542ed2095fd2e0041fedbfcff93
6
+ metadata.gz: 32bba980929441cb06022c829f73e7a7d8ee41de0dba07c98f44cb1f2c339dab87ec21dae8b1847ae2967e5771fb6506dd09a42a9540d784df4defd9f820f664
7
+ data.tar.gz: e1dc4e4e0e502b0747932b5b12011acfcb04535baeaae835027c50e1ec3ae1ff6ea7c0f6317469a8c4e11f8d9d9bfe40c530064ad4da5b4354231af1182776c6
data/CHANGELOG.md CHANGED
@@ -4,7 +4,20 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [1.1.0] - Unreleased
7
+ ## 1.1.2
8
+
9
+ ### Added
10
+ - Added thread to monitor child processes to make sure they exit after a SIGTERM signal has been sent. If a process does not exit after the configured Sidekiq timeout time, then it will be killed with a SIGKILL signal.
11
+
12
+ ### Changed
13
+ - A SIGINT sent to the manager process will sent SIGTERM to the child processes to give them a chance to shutdown gracefully.
14
+
15
+ ## 1.1.1
16
+
17
+ ### Added
18
+ - Guards to ensure signal processing thread doesn't die.
19
+
20
+ ## 1.1.0
8
21
 
9
22
  ### Added
10
23
  - Sidekiq 7 support.
@@ -15,17 +28,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
28
  - Sidekiq < 5.0 support.
16
29
  - Ruby < 2.5 support.
17
30
 
18
- ## [1.0.4] - 2021-05-20
31
+ ## 1.0.4
19
32
 
20
33
  ### Fixed
21
34
  - Set $0 to "sidekiq" in preforked process so instrumentation libraries detecting sidekiq server from the command line will work.
22
35
 
23
- ## [1.0.3] - 2021-05-19
36
+ ## 1.0.3
24
37
 
25
38
  ### Fixed
26
39
  - Restore bin dir to gem distribution.
27
40
 
28
- ## [1.0.2] - 2021-05-19
41
+ ## 1.0.2
29
42
 
30
43
  ### Added
31
44
  - Support for sidekiq >= 6.1.
@@ -34,12 +47,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
34
47
  ### Changed
35
48
  - Minimum Ruby version 2.3.
36
49
 
37
- ## [1.0.1] - 2020-02-20
50
+ ## 1.0.1
38
51
 
39
52
  ### Changed
40
53
  - Remove auto require of `sidekiq/cli` so `require: false` does not need to be specified in a Gemfile.
41
54
 
42
- ## [1.0.0] - 2019-11-27
55
+ ## 1.0.0
43
56
 
44
57
  ### Added
45
58
  - Initial release.
data/README.md CHANGED
@@ -8,7 +8,7 @@ This gem provides a command line script for managing [sidekiq](https://github.co
8
8
 
9
9
  The sidekiq processes can all be managed by sending signals to the manager process. This process simply forwards the signals on to the child processes, allowing you to control the sidekiq processes as you normally would.
10
10
 
11
- If one of the sidekiq processes dies unexpectedly, the process manager automatically starts a new sidekiq process to replace it.
11
+ If one of the sidekiq processes exits unexpectedly, the process manager automatically starts a new sidekiq process to replace it.
12
12
 
13
13
  ## Pre-Forking
14
14
 
@@ -44,7 +44,7 @@ For a Rails application, you would normally want to preboot the `config/boot.rb`
44
44
 
45
45
  ## Memory Bloat
46
46
 
47
- You can also specify a maximum memory footprint that you want to allow for each child process. You can use this feature to automatically guard against poorly designed workers that bloat the Ruby memory heap. Note that you can also use an external process monitor to kill processes with memory bloat; the process manager will restart any process regardless of how it dies.
47
+ You can also specify a maximum memory footprint that you want to allow for each child process. You can use this feature to automatically guard against poorly designed workers that bloat the Ruby memory heap. Note that you can also use an external process monitor to kill processes with memory bloat; the process manager will restart any process regardless of how it exits.
48
48
 
49
49
  ## Usage
50
50
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.1.2
@@ -64,28 +64,37 @@ module Sidekiq
64
64
 
65
65
  @signal_pipe_read, @signal_pipe_write = IO.pipe
66
66
 
67
+ @signal_thread = Thread.new do
68
+ Thread.current.name = "signal-handler"
69
+
70
+ while @signal_pipe_read.wait_readable
71
+ begin
72
+ signal = @signal_pipe_read.gets.strip
73
+ send_signal_to_children(signal.to_sym)
74
+ rescue => e
75
+ log_warning("Error sending signal #{signal} to child processes: #{e.message}")
76
+ end
77
+ end
78
+ end
79
+
67
80
  # Trap signals that will be forwarded to child processes
68
81
  [:INT, :TERM, :USR1, :USR2, :TSTP, :TTIN].each do |signal|
69
82
  ::Signal.trap(signal) do
70
83
  if ::Process.pid == master_pid
84
+ signal = :TERM if signal == :INT
71
85
  @signal_pipe_write.puts(signal)
72
86
  end
73
87
  end
74
88
  end
75
89
 
76
- @signal_thread = Thread.new do
77
- Thread.current.name = "signal-handler"
78
-
79
- while @signal_pipe_read.wait_readable
80
- signal = @signal_pipe_read.gets.strip
81
- send_signal_to_children(signal.to_sym)
82
- end
83
- end
84
-
85
90
  # Ensure that child processes receive the term signal when the master process exits.
86
91
  at_exit do
87
- if ::Process.pid == master_pid && @process_count > 0
88
- send_signal_to_children(:TERM)
92
+ if ::Process.pid == master_pid
93
+ if @process_count > 0
94
+ send_signal_to_children(:TERM)
95
+ end
96
+ wait_for_children_to_exit
97
+ log_info("Process manager exiting")
89
98
  end
90
99
  end
91
100
 
@@ -100,9 +109,8 @@ module Sidekiq
100
109
 
101
110
  start_memory_monitor if @max_memory
102
111
 
103
- log_info("Process manager started with pid #{::Process.pid}")
112
+ log_info("Process manager started")
104
113
  monitor_child_processes
105
- log_info("Process manager #{::Process.pid} exiting")
106
114
  end
107
115
 
108
116
  # Helper to wait on the manager to wait on child processes to start up.
@@ -143,15 +151,6 @@ module Sidekiq
143
151
  @started
144
152
  end
145
153
 
146
- # Kill a child process by sending the TERM signal to it.
147
- #
148
- # @param pid [Integer] The pid of the child process to kill.
149
- # @return [void]
150
- # @api private
151
- def kill(pid)
152
- ::Process.kill(:TERM, pid)
153
- end
154
-
155
154
  private
156
155
 
157
156
  def log_info(message)
@@ -242,14 +241,24 @@ module Sidekiq
242
241
  log_info("Process manager trapped signal #{signal}")
243
242
  @process_count = 0 if signal == :INT || signal == :TERM
244
243
  pids.each do |pid|
245
- begin
246
- log_info("Sending signal #{signal} to sidekiq process #{pid}")
247
- ::Process.kill(signal, pid)
248
- rescue => e
249
- log_warning("Error sending signal #{signal} to sidekiq process #{pid}: #{e.inspect}")
244
+ send_signal_to_pid(signal, pid)
245
+ end
246
+ end
247
+
248
+ def send_signal_to_pid(signal, pid)
249
+ signal = signal.to_sym
250
+ begin
251
+ log_info("Sending signal #{signal} to sidekiq process #{pid}")
252
+ ::Process.kill(signal, pid)
253
+ if [:TERM, :INT].include?(signal)
254
+ Thread.new do
255
+ Thread.current.name = "pid-#{pid}-killer"
256
+ ensure_pid_dies(pid)
257
+ end
250
258
  end
259
+ rescue Errno::ESRCH
260
+ # The process is already dead
251
261
  end
252
- wait_for_children_to_exit(pids) if @process_count == 0
253
262
  end
254
263
 
255
264
  def start_memory_monitor
@@ -264,8 +273,8 @@ module Sidekiq
264
273
  begin
265
274
  memory = GetProcessMem.new(pid)
266
275
  if memory.bytes > @max_memory
267
- log_warning("Kill bloated sidekiq process #{pid}: #{memory.mb.round}mb used")
268
- kill(pid)
276
+ log_warning("Killing bloated sidekiq process #{pid}: #{memory.mb.round}mb used")
277
+ send_signal_to_pid(:TERM, pid)
269
278
  break
270
279
  end
271
280
  rescue => e
@@ -282,18 +291,13 @@ module Sidekiq
282
291
  end
283
292
  end
284
293
 
285
- def wait_for_children_to_exit(pids)
286
- timeout = monotonic_time + (sidekiq_options[:timeout] || 25).to_f
294
+ def wait_for_children_to_exit
287
295
  pids.each do |pid|
288
- while monotonic_time < timeout
289
- break unless process_alive?(pid)
296
+ while process_alive?(pid)
290
297
  sleep(0.01)
291
298
  end
292
299
  end
293
-
294
- pids.each do |pid|
295
- ::Process.kill(:INT, pid) if process_alive?(pid)
296
- end
300
+ log_info("All sidekiq processes have exited")
297
301
  end
298
302
 
299
303
  def process_alive?(pid)
@@ -305,6 +309,24 @@ module Sidekiq
305
309
  end
306
310
  end
307
311
 
312
+ def ensure_pid_dies(pid)
313
+ # Wait for the process to die, or kill it after a timeout.
314
+ timeout = (sidekiq_options[:timeout] || 25).to_f
315
+ end_time = monotonic_time + timeout
316
+ while monotonic_time < end_time && process_alive?(pid)
317
+ sleep(0.1)
318
+ end
319
+
320
+ if process_alive?(pid)
321
+ begin
322
+ ::Process.kill(:KILL, pid)
323
+ log_warning("Sidekiq process #{pid} failed to exit after #{timeout} seconds; killed with SIGKILL")
324
+ rescue Errno::ESRCH
325
+ # The process is already dead
326
+ end
327
+ end
328
+ end
329
+
308
330
  # Listen for child processes dying and restart if necessary.
309
331
  def monitor_child_processes
310
332
  loop do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-process_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-19 00:00:00.000000000 Z
11
+ date: 2023-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq