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 +4 -4
- data/CHANGELOG.md +19 -6
- data/README.md +2 -2
- data/VERSION +1 -1
- data/lib/sidekiq/process_manager/manager.rb +60 -38
- 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,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
|
-
##
|
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
|
-
##
|
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
|
-
##
|
36
|
+
## 1.0.3
|
24
37
|
|
25
38
|
### Fixed
|
26
39
|
- Restore bin dir to gem distribution.
|
27
40
|
|
28
|
-
##
|
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
|
-
##
|
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
|
-
##
|
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
|
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
|
@@ -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
|
88
|
-
|
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
|
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
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
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("
|
268
|
-
|
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
|
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
|
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.
|
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
|