snipr 0.0.4 → 1.0.0
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 +5 -5
- data/README.md +21 -12
- data/bin/snipe +141 -0
- data/lib/snipr/version.rb +1 -1
- metadata +4 -4
- data/bin/reap_resque_workers +0 -107
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
SHA512:
|
3
|
-
metadata.gz: fa11945d45829fb5f7ef8d2bfc641109d18d6f238b233c16b1fa2a5e13e1a595164cf1933db78583e90d925b471b09662fab1b19bb63a74e6859a711310e3cd1
|
4
|
-
data.tar.gz: de1f5f425b757abd09630cc232a417db1ade1c8506042a41a7939e15ecd650789fabb827d7ccf4c3dba3ef2f7dfd280224ab0643ca02476b531dca8b6e29ff81
|
5
2
|
SHA1:
|
6
|
-
|
7
|
-
|
3
|
+
data.tar.gz: 0432d5218407fc9b0a154390e2ac486f87e6df94
|
4
|
+
metadata.gz: d415fed3259b55fbfaa03a951951f79ed5620fde
|
5
|
+
SHA512:
|
6
|
+
data.tar.gz: bc24aca5874832df60f75758f0958e96628af0bcedbb2ab7284dff51cadd46cc2af3c31e125f4808b7695cc25ad497e8be9291e71818fc6ddd3162ccda56f3e8
|
7
|
+
metadata.gz: cc023afbc9374259e1f1923b1c720e8ad6e1729fe9809c3adffb36855a849a76488f99f3e0b97812cfe25ef4a26057a1e03ce927089bd8c309dd2ca76b29bb4b
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
#### Culling Runaway Resque Workers
|
24
24
|
```
|
25
|
-
Usage:
|
25
|
+
Usage: snipe [options]
|
26
26
|
|
27
27
|
Can be used to reap runaway resque workers that have exceeded too much memory
|
28
28
|
use, CPU use, or time alive. By default, this sends USR1 to the parent worker
|
@@ -30,23 +30,32 @@ process, which causes it to immediately kill the runaway child. The parent
|
|
30
30
|
will then spawn another child to continue work.
|
31
31
|
|
32
32
|
Options:
|
33
|
-
-
|
34
|
-
|
35
|
-
-
|
36
|
-
|
33
|
+
-i, --include [PATTERN] Pattern that must be matched for a process
|
34
|
+
to be included
|
35
|
+
-e, --exclude [PATTERN] Pattern hat must NOT be matched for a
|
36
|
+
process to be included
|
37
|
+
-m, --memory [BYTES] Processes using more than some bytes size
|
38
|
+
of memory
|
39
|
+
-c, --cpu [PERCENTAGE] Processes using more than a percentage of
|
40
|
+
CPU
|
41
|
+
-a, --alive [SECONDS] Processes that have been alive for some
|
37
42
|
length of time in seconds
|
38
|
-
-s, --signal [SIGNAL] Signal to send to the
|
39
|
-
Defaults to
|
43
|
+
-s, --signal [SIGNAL] Signal to send to the targetted process or
|
44
|
+
its parent. Defaults to KILL.
|
40
45
|
-d, --dry-run Perform a dry run which will identify
|
41
|
-
|
42
|
-
signals
|
46
|
+
processes to be targetted but does not send
|
47
|
+
any signals
|
48
|
+
```
|
49
|
+
|
50
|
+
Here is an example of a command that we use at ShippingEasy to reap runaway
|
51
|
+
resque workers that have been running for longer than 24 hours:
|
52
|
+
|
53
|
+
```
|
54
|
+
snipe -i resque -i processing -e scheduler -a 86400
|
43
55
|
```
|
44
56
|
|
45
57
|
#### TODO
|
46
58
|
* Better readme docs
|
47
|
-
* General purpose command that lets you specify process filter options & signal
|
48
|
-
to send to arbitrary processes
|
49
|
-
* A command that targets bloated unicorn workers
|
50
59
|
|
51
60
|
## Contributing
|
52
61
|
|
data/bin/snipe
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require 'ostruct'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
options = OpenStruct.new({
|
6
|
+
:includes => [],
|
7
|
+
:excludes => [],
|
8
|
+
:signal => 'KILL',
|
9
|
+
:target_parent => false
|
10
|
+
})
|
11
|
+
|
12
|
+
parser = OptionParser.new do |config|
|
13
|
+
config.banner = "Usage: snipe [options]"
|
14
|
+
config.separator ""
|
15
|
+
config.separator "Target a process for signals using include/exclude regex"
|
16
|
+
config.separator "patterns and memory use, cpu use or time alive conditions."
|
17
|
+
config.separator "By default, this sends KILL (9) to the targetted process,"
|
18
|
+
config.separator "but options can be used to override the signal or to "
|
19
|
+
config.separator "target the parent process instead."
|
20
|
+
config.separator ""
|
21
|
+
config.separator "Options:"
|
22
|
+
|
23
|
+
desc = "Pattern that must be matched for a process to be included"
|
24
|
+
config.on("-i", "--include [PATTERN]", desc) do |pattern|
|
25
|
+
options.includes << /#{pattern}/i
|
26
|
+
end
|
27
|
+
|
28
|
+
desc = "Pattern that must NOT be matched for a process to be included"
|
29
|
+
config.on("-e", "--exclude [PATTERN]", desc) do |pattern|
|
30
|
+
options.excludes << /#{pattern}/i
|
31
|
+
end
|
32
|
+
|
33
|
+
desc = "Processes using more than some bytes size of memory"
|
34
|
+
config.on("-m", "--memory [BYTES]", desc) do |bytes|
|
35
|
+
options.bytes = bytes.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
desc = "Processes using more than a percentage of CPU"
|
39
|
+
config.on("-c", "--cpu [PERCENTAGE]", desc) do |cpu|
|
40
|
+
options.cpu = cpu.to_f
|
41
|
+
end
|
42
|
+
|
43
|
+
desc = "Processes that have been alive for some length of time in seconds"
|
44
|
+
config.on("-a", "--alive [SECONDS]", desc) do |sec|
|
45
|
+
options.alive = sec.to_i
|
46
|
+
end
|
47
|
+
|
48
|
+
desc = "Signal to send to the targetted process or its parent. Defaults to KILL."
|
49
|
+
config.on("-s", "--signal [SIGNAL]", desc) do |signal|
|
50
|
+
options.signal = signal
|
51
|
+
end
|
52
|
+
|
53
|
+
desc = "Send the signal to the parent of the targetted process"
|
54
|
+
config.on("-p", "--parent", desc) do
|
55
|
+
options.target_parent = true
|
56
|
+
end
|
57
|
+
|
58
|
+
desc = "Perform a dry run which will identify processes to be targetted but not send any signals"
|
59
|
+
config.on("-d", "--dry-run", desc) do
|
60
|
+
options.no_signals = true
|
61
|
+
end
|
62
|
+
end.parse!
|
63
|
+
|
64
|
+
# TODO remove me
|
65
|
+
$: << 'lib'
|
66
|
+
|
67
|
+
require 'snipr'
|
68
|
+
output = Snipr::Output.new
|
69
|
+
|
70
|
+
if options.includes.empty?
|
71
|
+
output.err("error - You must specify an include pattern with -i")
|
72
|
+
Kernel.exit(-1)
|
73
|
+
end
|
74
|
+
|
75
|
+
unless options.bytes || options.keys || options.alive
|
76
|
+
output.err("error - You must specify at least one of -m, -c or -a")
|
77
|
+
Kernel.exit(-1)
|
78
|
+
end
|
79
|
+
|
80
|
+
output.info("*** DRY RUN ***") if options.no_signals
|
81
|
+
|
82
|
+
signaller = Snipr::ProcessSignaller.new do |signaller|
|
83
|
+
options.includes.each do |pattern|
|
84
|
+
signaller.include pattern
|
85
|
+
end
|
86
|
+
options.excludes.each do |pattern|
|
87
|
+
signaller.exclude pattern
|
88
|
+
end
|
89
|
+
signaller.signal options.signal
|
90
|
+
signaller.target_parent options.target_parent
|
91
|
+
signaller.dry_run if options.no_signals
|
92
|
+
|
93
|
+
if options.bytes
|
94
|
+
signaller.memory_greater_than(options.bytes)
|
95
|
+
end
|
96
|
+
|
97
|
+
if options.cpu
|
98
|
+
signaller.cpu_greater_than(options.cpu)
|
99
|
+
end
|
100
|
+
|
101
|
+
if options.alive
|
102
|
+
signaller.alive_longer_than(options.alive)
|
103
|
+
end
|
104
|
+
|
105
|
+
signaller.on_no_processes do
|
106
|
+
output.info("no runaways found")
|
107
|
+
end
|
108
|
+
|
109
|
+
signaller.after_signal do |signal, process|
|
110
|
+
if options.target_parent
|
111
|
+
msg = "sent #{signal} to process #{process.ppid} to act on child " +
|
112
|
+
"#{process.pid}"
|
113
|
+
else
|
114
|
+
msg = "sent #{signal} to process #{process.pid}"
|
115
|
+
end
|
116
|
+
|
117
|
+
output.info(msg)
|
118
|
+
|
119
|
+
msg = "memory:#{process.memory} cpu:#{process.cpu} time_alive: " +
|
120
|
+
"#{process.seconds_alive} command: #{process.command}"
|
121
|
+
output.info(msg)
|
122
|
+
end
|
123
|
+
|
124
|
+
signaller.on_error do |error, signal, process|
|
125
|
+
raise error
|
126
|
+
if signal && process
|
127
|
+
if options.target_parent
|
128
|
+
msg = "error sending #{signal} to #{process.ppid} to act on " +
|
129
|
+
"#{process.pid}: #{error}"
|
130
|
+
else
|
131
|
+
msg = "error sending #{signal} to #{process.pid}: #{error}"
|
132
|
+
end
|
133
|
+
else
|
134
|
+
msg = "error: #{error}"
|
135
|
+
end
|
136
|
+
output.err(msg)
|
137
|
+
Kernel.exit(-1)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
signaller.send_signals
|
data/lib/snipr/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snipr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lance Woodson
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-11-25 00:00:00 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -60,7 +60,7 @@ description: |
|
|
60
60
|
email:
|
61
61
|
- lance@webmaneuvers.com
|
62
62
|
executables:
|
63
|
-
-
|
63
|
+
- snipe
|
64
64
|
extensions: []
|
65
65
|
|
66
66
|
extra_rdoc_files: []
|
@@ -73,7 +73,7 @@ files:
|
|
73
73
|
- LICENSE.txt
|
74
74
|
- README.md
|
75
75
|
- Rakefile
|
76
|
-
- bin/
|
76
|
+
- bin/snipe
|
77
77
|
- lib/snipr.rb
|
78
78
|
- lib/snipr/output.rb
|
79
79
|
- lib/snipr/process_locator.rb
|
data/bin/reap_resque_workers
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
#!/usr/bin/ruby
|
2
|
-
require 'ostruct'
|
3
|
-
require 'optparse'
|
4
|
-
|
5
|
-
options = OpenStruct.new({
|
6
|
-
:signal => 'USR1'
|
7
|
-
})
|
8
|
-
|
9
|
-
parser = OptionParser.new do |config|
|
10
|
-
config.banner = "Usage: reap_resque_workers [options]"
|
11
|
-
config.separator ""
|
12
|
-
config.separator "Can be used to reap runaway resque workers " +
|
13
|
-
"that have exceeded too much memory use, " +
|
14
|
-
"CPU use, or time alive."
|
15
|
-
config.separator "By default, this sends USR1 to the parent worker " +
|
16
|
-
"process, which causes it to immediately kill " +
|
17
|
-
"the runaway"
|
18
|
-
config.separator "child. The parent will then spawn another child to " +
|
19
|
-
"continue work."
|
20
|
-
config.separator ""
|
21
|
-
config.separator "Options:"
|
22
|
-
|
23
|
-
desc = "Workers using more than some bytes size of memory"
|
24
|
-
config.on("-m", "--memory [BYTES]", desc) do |bytes|
|
25
|
-
options.bytes = bytes.to_i
|
26
|
-
end
|
27
|
-
|
28
|
-
desc = "workers using more than a percentage of CPU"
|
29
|
-
config.on("-c", "--cpu [PERCENTAGE]", desc) do |cpu|
|
30
|
-
options.cpu = cpu.to_f
|
31
|
-
end
|
32
|
-
|
33
|
-
desc = "Workers that have been alive for some length of time in seconds"
|
34
|
-
config.on("-a", "--alive [SECONDS]", desc) do |sec|
|
35
|
-
options.alive = sec.to_i
|
36
|
-
end
|
37
|
-
|
38
|
-
desc = "Signal to send to the worker's parent. Defaults to USR1."
|
39
|
-
config.on("-s", "--signal [SIGNAL]", desc) do |signal|
|
40
|
-
options.signal = signal
|
41
|
-
end
|
42
|
-
|
43
|
-
desc = "Perform a dry run which will identify workers to be reaped but not send any signals"
|
44
|
-
config.on("-d", "--dry-run", desc) do
|
45
|
-
options.no_signals = true
|
46
|
-
end
|
47
|
-
end.parse!
|
48
|
-
|
49
|
-
# TODO remove me
|
50
|
-
$: << 'lib'
|
51
|
-
|
52
|
-
require 'snipr'
|
53
|
-
output = Snipr::Output.new
|
54
|
-
|
55
|
-
unless options.bytes || options.keys || options.alive
|
56
|
-
output.err("error - You must specify at least one of -m, -c or -a")
|
57
|
-
Kernel.exit(-1)
|
58
|
-
end
|
59
|
-
|
60
|
-
output.info("*** DRY RUN ***") if options.no_signals
|
61
|
-
|
62
|
-
signaller = Snipr::ProcessSignaller.new do |signaller|
|
63
|
-
signaller.signal options.signal
|
64
|
-
signaller.target_parent true
|
65
|
-
signaller.include /resque/
|
66
|
-
signaller.include /processing/i
|
67
|
-
signaller.exclude /scheduler/i
|
68
|
-
signaller.dry_run if options.no_signals
|
69
|
-
|
70
|
-
if options.bytes
|
71
|
-
signaller.memory_greater_than(options.bytes)
|
72
|
-
end
|
73
|
-
|
74
|
-
if options.cpu
|
75
|
-
signaller.cpu_greater_than(options.cpu)
|
76
|
-
end
|
77
|
-
|
78
|
-
if options.alive
|
79
|
-
signaller.alive_longer_than(options.alive)
|
80
|
-
end
|
81
|
-
|
82
|
-
signaller.on_no_processes do
|
83
|
-
output.info("no runaways found")
|
84
|
-
end
|
85
|
-
|
86
|
-
signaller.after_signal do |signal, process|
|
87
|
-
msg = "sent #{signal} to worker #{process.ppid} to gracefully shutdown " +
|
88
|
-
"child #{process.pid}"
|
89
|
-
output.info(msg)
|
90
|
-
|
91
|
-
msg = "memory:#{process.memory} cpu:#{process.cpu} time_alive: " +
|
92
|
-
"#{process.seconds_alive} command: #{process.command}"
|
93
|
-
output.info(msg)
|
94
|
-
end
|
95
|
-
|
96
|
-
signaller.on_error do |error, signal, process|
|
97
|
-
raise error
|
98
|
-
if signal && process
|
99
|
-
output.err("error sending #{signal} to #{process.ppid} to gracefully shutdown #{process.pid}: #{error}")
|
100
|
-
else
|
101
|
-
output.err("error: #{error}")
|
102
|
-
Kernel.exit(-1)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
signaller.send_signals
|