sidekiq-process_manager 1.1.1 → 1.1.2
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 +2 -2
- data/VERSION +1 -1
- data/lib/sidekiq/process_manager/manager.rb +48 -29
- 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: dc25ffae388e5ca7ad73f0976d00cf09ec84124b2284a000af1dc0970cf87c20
|
4
|
+
data.tar.gz: 94637ae3cfa8a6fa991e95ee434c8410936c62263695f36b6db8c2b664d1f439
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32bba980929441cb06022c829f73e7a7d8ee41de0dba07c98f44cb1f2c339dab87ec21dae8b1847ae2967e5771fb6506dd09a42a9540d784df4defd9f820f664
|
7
|
+
data.tar.gz: e1dc4e4e0e502b0747932b5b12011acfcb04535baeaae835027c50e1ec3ae1ff6ea7c0f6317469a8c4e11f8d9d9bfe40c530064ad4da5b4354231af1182776c6
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,14 @@ 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.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
|
+
|
7
15
|
## 1.1.1
|
8
16
|
|
9
17
|
### Added
|
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
|
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
|
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.
|
1
|
+
1.1.2
|
@@ -72,7 +72,7 @@ module Sidekiq
|
|
72
72
|
signal = @signal_pipe_read.gets.strip
|
73
73
|
send_signal_to_children(signal.to_sym)
|
74
74
|
rescue => e
|
75
|
-
|
75
|
+
log_warning("Error sending signal #{signal} to child processes: #{e.message}")
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
@@ -81,6 +81,7 @@ module Sidekiq
|
|
81
81
|
[:INT, :TERM, :USR1, :USR2, :TSTP, :TTIN].each do |signal|
|
82
82
|
::Signal.trap(signal) do
|
83
83
|
if ::Process.pid == master_pid
|
84
|
+
signal = :TERM if signal == :INT
|
84
85
|
@signal_pipe_write.puts(signal)
|
85
86
|
end
|
86
87
|
end
|
@@ -88,8 +89,12 @@ module Sidekiq
|
|
88
89
|
|
89
90
|
# Ensure that child processes receive the term signal when the master process exits.
|
90
91
|
at_exit do
|
91
|
-
if ::Process.pid == master_pid
|
92
|
-
|
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")
|
93
98
|
end
|
94
99
|
end
|
95
100
|
|
@@ -104,9 +109,8 @@ module Sidekiq
|
|
104
109
|
|
105
110
|
start_memory_monitor if @max_memory
|
106
111
|
|
107
|
-
log_info("Process manager started
|
112
|
+
log_info("Process manager started")
|
108
113
|
monitor_child_processes
|
109
|
-
log_info("Process manager #{::Process.pid} exiting")
|
110
114
|
end
|
111
115
|
|
112
116
|
# Helper to wait on the manager to wait on child processes to start up.
|
@@ -237,14 +241,24 @@ module Sidekiq
|
|
237
241
|
log_info("Process manager trapped signal #{signal}")
|
238
242
|
@process_count = 0 if signal == :INT || signal == :TERM
|
239
243
|
pids.each do |pid|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
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
|
245
258
|
end
|
259
|
+
rescue Errno::ESRCH
|
260
|
+
# The process is already dead
|
246
261
|
end
|
247
|
-
wait_for_children_to_exit(pids) if @process_count == 0
|
248
262
|
end
|
249
263
|
|
250
264
|
def start_memory_monitor
|
@@ -259,12 +273,8 @@ module Sidekiq
|
|
259
273
|
begin
|
260
274
|
memory = GetProcessMem.new(pid)
|
261
275
|
if memory.bytes > @max_memory
|
262
|
-
log_warning("
|
263
|
-
|
264
|
-
::Process.kill(:TERM, pid)
|
265
|
-
rescue Errno::ESRCH
|
266
|
-
# The process is already dead
|
267
|
-
end
|
276
|
+
log_warning("Killing bloated sidekiq process #{pid}: #{memory.mb.round}mb used")
|
277
|
+
send_signal_to_pid(:TERM, pid)
|
268
278
|
break
|
269
279
|
end
|
270
280
|
rescue => e
|
@@ -281,22 +291,13 @@ module Sidekiq
|
|
281
291
|
end
|
282
292
|
end
|
283
293
|
|
284
|
-
def wait_for_children_to_exit
|
285
|
-
timeout = monotonic_time + (sidekiq_options[:timeout] || 25).to_f
|
294
|
+
def wait_for_children_to_exit
|
286
295
|
pids.each do |pid|
|
287
|
-
while
|
288
|
-
break unless process_alive?(pid)
|
296
|
+
while process_alive?(pid)
|
289
297
|
sleep(0.01)
|
290
298
|
end
|
291
299
|
end
|
292
|
-
|
293
|
-
pids.each do |pid|
|
294
|
-
begin
|
295
|
-
::Process.kill(:INT, pid) if process_alive?(pid)
|
296
|
-
rescue
|
297
|
-
# Ignore errors so we can continue to kill other processes.
|
298
|
-
end
|
299
|
-
end
|
300
|
+
log_info("All sidekiq processes have exited")
|
300
301
|
end
|
301
302
|
|
302
303
|
def process_alive?(pid)
|
@@ -308,6 +309,24 @@ module Sidekiq
|
|
308
309
|
end
|
309
310
|
end
|
310
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
|
+
|
311
330
|
# Listen for child processes dying and restart if necessary.
|
312
331
|
def monitor_child_processes
|
313
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.
|
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-
|
11
|
+
date: 2023-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|