snipr 0.0.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|