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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA512:
3
- metadata.gz: fa11945d45829fb5f7ef8d2bfc641109d18d6f238b233c16b1fa2a5e13e1a595164cf1933db78583e90d925b471b09662fab1b19bb63a74e6859a711310e3cd1
4
- data.tar.gz: de1f5f425b757abd09630cc232a417db1ade1c8506042a41a7939e15ecd650789fabb827d7ccf4c3dba3ef2f7dfd280224ab0643ca02476b531dca8b6e29ff81
5
2
  SHA1:
6
- metadata.gz: a133c18251342f631b0a254bce7546f26ff97e80
7
- data.tar.gz: 48a55cc801d8f376bdb0cc7302eea605153e5a90
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: reap_resque_workers [options]
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
- -m, --memory [BYTES] Workers using more than some bytes size of
34
- memory
35
- -c, --cpu [PERCENTAGE] workers using more than a percentage of CPU
36
- -a, --alive [SECONDS] Workers that have been alive for some
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 worker's parent.
39
- Defaults to USR1.
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
- workers to be reaped but not send any
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
 
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Snipr
2
- VERSION = "0.0.4"
2
+ VERSION = "1.0.0"
3
3
  end
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
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-09-09 00:00:00 Z
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
- - reap_resque_workers
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/reap_resque_workers
76
+ - bin/snipe
77
77
  - lib/snipr.rb
78
78
  - lib/snipr/output.rb
79
79
  - lib/snipr/process_locator.rb
@@ -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