snipr 0.0.1
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 +7 -0
 - data/.gitignore +14 -0
 - data/.ruby-gemset +1 -0
 - data/.ruby-version +1 -0
 - data/Gemfile +4 -0
 - data/LICENSE.txt +22 -0
 - data/README.md +44 -0
 - data/Rakefile +2 -0
 - data/bin/reap_resque_workers +99 -0
 - data/lib/snipr.rb +24 -0
 - data/lib/snipr/output.rb +27 -0
 - data/lib/snipr/process_locator.rb +134 -0
 - data/lib/snipr/process_signaller.rb +113 -0
 - data/lib/snipr/version.rb +3 -0
 - data/snipr.gemspec +29 -0
 - data/spec/process_locator_spec.rb +123 -0
 - data/spec/process_signaller_spec.rb +100 -0
 - data/spec/ps_output.txt +53 -0
 - data/spec/spec_helper.rb +2 -0
 - metadata +114 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- 
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA512: 
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 0431e21ba622f828ce67bbef64c3ea2bd900e9dac1e6069dbeb88feb0389c6837f9dd1a5654918dd3a2059b69ce52c836927522ea5f1a6c4aa5bec1f74d51bd3
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: f2f45b0e24e2576610dd7883ac64b9828dd2ef6586320399d77832b54a597183a297e11e18a252a93130179c86cb11da4d7c610b9d4b90d5acb6a86afb5421ea
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA1: 
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: e4ba65cbad1a2cd5acb11c37237b5f843328a176
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 9ab5063ba228c17e50ab64634c58efea2fc6aee4
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.ruby-gemset
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            snipr
         
     | 
    
        data/.ruby-version
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ruby-1.8.7-p374
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2014 Lance Woodson
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            MIT License
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 6 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 7 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 8 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 9 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 10 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 11 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 14 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 17 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 18 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 19 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 20 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 21 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 22 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Snipr
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Tool to manage runaway processes.  More to be written later.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 10 
     | 
    
         
            +
            gem 'snipr'
         
     | 
| 
      
 11 
     | 
    
         
            +
            ```
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                $ bundle
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                $ gem install snipr
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            #### Culling Runaway Resque Workers
         
     | 
| 
      
 24 
     | 
    
         
            +
            ```
         
     | 
| 
      
 25 
     | 
    
         
            +
            Usage: reap_resque_workers [options]
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            Can be used to reap runaway resque workers that have exceeded too much memory use, CPU use, or time alive.
         
     | 
| 
      
 28 
     | 
    
         
            +
            By default, this sends USR1 to the parent worker process, which causes it to immediately kill the runaway
         
     | 
| 
      
 29 
     | 
    
         
            +
            child.  The parent will then spawn another child to continue work.
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            Options:
         
     | 
| 
      
 32 
     | 
    
         
            +
                -m, --memory [BYTES]             Workers using more than some bytes size of memory
         
     | 
| 
      
 33 
     | 
    
         
            +
                -c, --cpu [PERCENTAGE]           workers using more than a percentage of CPU
         
     | 
| 
      
 34 
     | 
    
         
            +
                -a, --alive [SECONDS]            Workers that have been alive for some length of time in seconds
         
     | 
| 
      
 35 
     | 
    
         
            +
                -s, --signal [SIGNAL]            Signal to send to the worker's parent.  Defaults to USR1.
         
     | 
| 
      
 36 
     | 
    
         
            +
            ```
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            1. Fork it ( https://github.com/[my-github-username]/snipr/fork )
         
     | 
| 
      
 41 
     | 
    
         
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
      
 42 
     | 
    
         
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         
     | 
| 
      
 43 
     | 
    
         
            +
            4. Push to the branch (`git push origin my-new-feature`)
         
     | 
| 
      
 44 
     | 
    
         
            +
            5. Create a new Pull Request
         
     | 
    
        data/Rakefile
    ADDED
    
    
| 
         @@ -0,0 +1,99 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env 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 
     | 
    
         
            +
            end.parse!
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            # TODO remove me
         
     | 
| 
      
 45 
     | 
    
         
            +
            $: << 'lib'
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            require 'snipr'
         
     | 
| 
      
 48 
     | 
    
         
            +
            output = Snipr::Output.new
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            unless options.bytes || options.keys || options.alive
         
     | 
| 
      
 51 
     | 
    
         
            +
              output.err("error - You must specify at least one of -m, -c or -a")
         
     | 
| 
      
 52 
     | 
    
         
            +
              Kernel.exit(-1)
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            signaller = Snipr::ProcessSignaller.new do |signaller|
         
     | 
| 
      
 56 
     | 
    
         
            +
              signaller.signal          options.signal
         
     | 
| 
      
 57 
     | 
    
         
            +
              signaller.target_parent   true
         
     | 
| 
      
 58 
     | 
    
         
            +
              signaller.include         /resque/
         
     | 
| 
      
 59 
     | 
    
         
            +
              signaller.include         /processing/i
         
     | 
| 
      
 60 
     | 
    
         
            +
              signaller.exclude         /scheduler/i
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              if options.bytes
         
     | 
| 
      
 63 
     | 
    
         
            +
                signaller.memory_greater_than(options.bytes)
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              if options.cpu
         
     | 
| 
      
 67 
     | 
    
         
            +
                signaller.cpu_greater_than(options.cpu)
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
              if options.alive
         
     | 
| 
      
 71 
     | 
    
         
            +
                signaller.alive_longer_than(options.alive)
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              signaller.on_no_processes do
         
     | 
| 
      
 75 
     | 
    
         
            +
                output.info("no runaways found")
         
     | 
| 
      
 76 
     | 
    
         
            +
              end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
              signaller.after_signal do |signal, process|
         
     | 
| 
      
 79 
     | 
    
         
            +
                msg = "sent #{signal} to worker #{process.ppid} to gracefully shutdown " +
         
     | 
| 
      
 80 
     | 
    
         
            +
                      "child #{process.pid}"
         
     | 
| 
      
 81 
     | 
    
         
            +
                output.info(msg)
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                msg = "memory:#{process.memory} cpu:#{process.cpu} time_alive: " +
         
     | 
| 
      
 84 
     | 
    
         
            +
                      "#{process.seconds_alive} command: #{process.command}"
         
     | 
| 
      
 85 
     | 
    
         
            +
                output.info(msg)
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
              signaller.on_error do |error, signal, process|
         
     | 
| 
      
 89 
     | 
    
         
            +
                raise error
         
     | 
| 
      
 90 
     | 
    
         
            +
                if signal && process
         
     | 
| 
      
 91 
     | 
    
         
            +
                  output.err("error sending #{signal} to #{process.ppid} to gracefully shutdown #{process.pid}: #{error}")
         
     | 
| 
      
 92 
     | 
    
         
            +
                else
         
     | 
| 
      
 93 
     | 
    
         
            +
                  output.err("error: #{error}")
         
     | 
| 
      
 94 
     | 
    
         
            +
                  Kernel.exit(-1)
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
            end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
            signaller.send_signals
         
     | 
    
        data/lib/snipr.rb
    ADDED
    
    | 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'open3'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'snipr/version'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'snipr/output'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'snipr/process_locator'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'snipr/process_signaller'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Snipr
         
     | 
| 
      
 9 
     | 
    
         
            +
              ##
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Error raised when a system command fails
         
     | 
| 
      
 11 
     | 
    
         
            +
              class ExecError < StandardError; end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              ##
         
     | 
| 
      
 14 
     | 
    
         
            +
              # Executes a command, returning the output as
         
     | 
| 
      
 15 
     | 
    
         
            +
              # an array of lines.  Raises an ExecError if the
         
     | 
| 
      
 16 
     | 
    
         
            +
              # command did not execute cleanly.
         
     | 
| 
      
 17 
     | 
    
         
            +
              def self.exec_cmd(command)
         
     | 
| 
      
 18 
     | 
    
         
            +
                Open3.popen3(command) do |stdin, stdout, stderr|
         
     | 
| 
      
 19 
     | 
    
         
            +
                  err = stderr.read
         
     | 
| 
      
 20 
     | 
    
         
            +
                  raise ExecError, err unless err.empty?
         
     | 
| 
      
 21 
     | 
    
         
            +
                  stdout.read.split("\n")
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/snipr/output.rb
    ADDED
    
    | 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'time'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Snipr
         
     | 
| 
      
 4 
     | 
    
         
            +
              ##
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Class for writing to standard error & standard out in a
         
     | 
| 
      
 6 
     | 
    
         
            +
              # uniform way.
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Output
         
     | 
| 
      
 8 
     | 
    
         
            +
                ##
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Write a message prepended with an ISO8601 timestamp to
         
     | 
| 
      
 10 
     | 
    
         
            +
                # STDOUT
         
     | 
| 
      
 11 
     | 
    
         
            +
                def info(msg)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  STDOUT.write("#{runtime} #{msg}\n")
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                ##
         
     | 
| 
      
 16 
     | 
    
         
            +
                # Write a message prepndend with an ISO8601 timestamp to
         
     | 
| 
      
 17 
     | 
    
         
            +
                # STDERR
         
     | 
| 
      
 18 
     | 
    
         
            +
                def err(msg)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  STDERR.write("#{runtime} #{msg}\n")
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                private
         
     | 
| 
      
 23 
     | 
    
         
            +
                def runtime
         
     | 
| 
      
 24 
     | 
    
         
            +
                  Time.now.iso8601
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,134 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Snipr
         
     | 
| 
      
 2 
     | 
    
         
            +
              ##
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Simple data structure representing a kernel process
         
     | 
| 
      
 4 
     | 
    
         
            +
              KernelProcess = Struct.new(:pid,:ppid,:memory,:cpu,:etime,:seconds_alive,:command)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              ##
         
     | 
| 
      
 7 
     | 
    
         
            +
              # Responsible for locating running processes and returning an array
         
     | 
| 
      
 8 
     | 
    
         
            +
              # of KernelProcess objects that represent them.  Uses the output of
         
     | 
| 
      
 9 
     | 
    
         
            +
              # ps to locate processes, so this only works on *nix.  Tested on
         
     | 
| 
      
 10 
     | 
    
         
            +
              # RHEL 6.5 and Linux Mint
         
     | 
| 
      
 11 
     | 
    
         
            +
              class ProcessLocator
         
     | 
| 
      
 12 
     | 
    
         
            +
                DAY_SECONDS = 86400
         
     | 
| 
      
 13 
     | 
    
         
            +
                HOUR_SECONDS = 3600
         
     | 
| 
      
 14 
     | 
    
         
            +
                MINUTE_SECONDS = 60
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                attr_accessor :signal
         
     | 
| 
      
 18 
     | 
    
         
            +
                attr_reader :includes, :excludes, :filters
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @includes = []
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @excludes = []
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @filters = []
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                ##
         
     | 
| 
      
 27 
     | 
    
         
            +
                # Locates the processes that match all include patterns and do not
         
     | 
| 
      
 28 
     | 
    
         
            +
                # match all exclude patterns
         
     | 
| 
      
 29 
     | 
    
         
            +
                def locate
         
     | 
| 
      
 30 
     | 
    
         
            +
                  processes = includes.reduce(all_processes, &by_inclusion_patterns)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  processes = excludes.reduce(processes, &by_exclusion_patterns)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  processes = filters.reduce(processes, &by_filter)
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                ##
         
     | 
| 
      
 36 
     | 
    
         
            +
                # Define a pattern that the command portion of the ps command must match to
         
     | 
| 
      
 37 
     | 
    
         
            +
                # include the process.  Multiple patterns can be defined and all must be
         
     | 
| 
      
 38 
     | 
    
         
            +
                # matched
         
     | 
| 
      
 39 
     | 
    
         
            +
                def include(pattern)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  includes << pattern
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                ##
         
     | 
| 
      
 44 
     | 
    
         
            +
                # Define a pattern that the command portion of the ps command must match to
         
     | 
| 
      
 45 
     | 
    
         
            +
                # exclude the process.  Multiple patterns can be defined and all will be
         
     | 
| 
      
 46 
     | 
    
         
            +
                # rejected.
         
     | 
| 
      
 47 
     | 
    
         
            +
                def exclude(pattern)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  excludes << pattern
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                ##
         
     | 
| 
      
 52 
     | 
    
         
            +
                # Define a size in bytes that processes must be greater than to be included
         
     | 
| 
      
 53 
     | 
    
         
            +
                # in the result.
         
     | 
| 
      
 54 
     | 
    
         
            +
                def memory_greater_than(bytes)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  filter { |process| process.memory > bytes }
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                ##
         
     | 
| 
      
 59 
     | 
    
         
            +
                # Define a cpu use percentage that processes must be greater than to be
         
     | 
| 
      
 60 
     | 
    
         
            +
                # included in the result.
         
     | 
| 
      
 61 
     | 
    
         
            +
                def cpu_greater_than(percent)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  filter {|process| process.cpu > percent}
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                ##
         
     | 
| 
      
 66 
     | 
    
         
            +
                # Define a time in seconds that processes must have been alive for longer
         
     | 
| 
      
 67 
     | 
    
         
            +
                # than to be included in results
         
     | 
| 
      
 68 
     | 
    
         
            +
                def alive_longer_than(sec)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  filter {|process| process.seconds_alive > sec}
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                ##
         
     | 
| 
      
 73 
     | 
    
         
            +
                # Define your own filter using a lambda that receives a KernelProcess object
         
     | 
| 
      
 74 
     | 
    
         
            +
                # and returns true if the process should be included in results
         
     | 
| 
      
 75 
     | 
    
         
            +
                def filter(&callable)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  filters << callable
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                private
         
     | 
| 
      
 80 
     | 
    
         
            +
                def clear!
         
     | 
| 
      
 81 
     | 
    
         
            +
                  @includes = []
         
     | 
| 
      
 82 
     | 
    
         
            +
                  @excludes = []
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def by_inclusion_patterns
         
     | 
| 
      
 86 
     | 
    
         
            +
                  lambda {|processes, filter| processes.select(&match(filter))}
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                def by_exclusion_patterns
         
     | 
| 
      
 90 
     | 
    
         
            +
                  lambda {|processes, filter| processes.reject(&match(filter))}
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                def by_filter
         
     | 
| 
      
 94 
     | 
    
         
            +
                  lambda {|processes, filter| processes.select(&filter)}
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                def match(filter)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  lambda {|process| process.command.match(filter)}
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                def all_processes
         
     | 
| 
      
 102 
     | 
    
         
            +
                  Snipr.exec_cmd('ps h -eo pid,ppid,size,%cpu,etime,cmd').map do |line|
         
     | 
| 
      
 103 
     | 
    
         
            +
                    pid, ppid, mem, cpu, etime, *cmd = line.split
         
     | 
| 
      
 104 
     | 
    
         
            +
                    cmd = cmd.join(" ")
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    KernelProcess.new(
         
     | 
| 
      
 107 
     | 
    
         
            +
                      pid.to_i,
         
     | 
| 
      
 108 
     | 
    
         
            +
                      ppid.to_i,
         
     | 
| 
      
 109 
     | 
    
         
            +
                      mem.to_i,
         
     | 
| 
      
 110 
     | 
    
         
            +
                      cpu.to_f,
         
     | 
| 
      
 111 
     | 
    
         
            +
                      etime,
         
     | 
| 
      
 112 
     | 
    
         
            +
                      parse_seconds(etime),
         
     | 
| 
      
 113 
     | 
    
         
            +
                      cmd
         
     | 
| 
      
 114 
     | 
    
         
            +
                    )
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                ##
         
     | 
| 
      
 119 
     | 
    
         
            +
                # Parses etime, which is in the format dd-hh:mm:ss
         
     | 
| 
      
 120 
     | 
    
         
            +
                # dd- will be omitted if the run time is < 24 hours
         
     | 
| 
      
 121 
     | 
    
         
            +
                # hh: will be omitted if the run time is < 1 hour
         
     | 
| 
      
 122 
     | 
    
         
            +
                def parse_seconds(etime)
         
     | 
| 
      
 123 
     | 
    
         
            +
                  time, days = etime.split("-").reverse
         
     | 
| 
      
 124 
     | 
    
         
            +
                  sec, min, hr = time.split(":").reverse
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  total = 0
         
     | 
| 
      
 127 
     | 
    
         
            +
                  total += days.to_i * DAY_SECONDS if days
         
     | 
| 
      
 128 
     | 
    
         
            +
                  total += hr.to_i * HOUR_SECONDS if hr
         
     | 
| 
      
 129 
     | 
    
         
            +
                  total += min.to_i * MINUTE_SECONDS if min
         
     | 
| 
      
 130 
     | 
    
         
            +
                  total += sec.to_i if sec
         
     | 
| 
      
 131 
     | 
    
         
            +
                  total
         
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
              end
         
     | 
| 
      
 134 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,113 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'forwardable'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Snipr
         
     | 
| 
      
 4 
     | 
    
         
            +
              ##
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Class that can send signals to targetted processes or their
         
     | 
| 
      
 6 
     | 
    
         
            +
              # parent processes and invoke callbacks around the actions.  Delegates
         
     | 
| 
      
 7 
     | 
    
         
            +
              # process location to a ProcessLocator.  Is configured using a
         
     | 
| 
      
 8 
     | 
    
         
            +
              # block on initialization as follows:
         
     | 
| 
      
 9 
     | 
    
         
            +
              #
         
     | 
| 
      
 10 
     | 
    
         
            +
              # signaller = ProcessSignaller.new do |signaller|
         
     | 
| 
      
 11 
     | 
    
         
            +
              #   signaller.include       /resque/
         
     | 
| 
      
 12 
     | 
    
         
            +
              #   signaller.exclude       /scheduler/
         
     | 
| 
      
 13 
     | 
    
         
            +
              #   signaller.signal        "USR1"
         
     | 
| 
      
 14 
     | 
    
         
            +
              #   signaller.target_parent false
         
     | 
| 
      
 15 
     | 
    
         
            +
              #
         
     | 
| 
      
 16 
     | 
    
         
            +
              #   signaller.on_no_processes do
         
     | 
| 
      
 17 
     | 
    
         
            +
              #     puts "No processes"
         
     | 
| 
      
 18 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 19 
     | 
    
         
            +
              #
         
     | 
| 
      
 20 
     | 
    
         
            +
              #   signaller.before_signal do |signal, process|
         
     | 
| 
      
 21 
     | 
    
         
            +
              #     puts "Sending #{signal} to #{process.pid}"
         
     | 
| 
      
 22 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 23 
     | 
    
         
            +
              #
         
     | 
| 
      
 24 
     | 
    
         
            +
              #   signaller.after_signal do |signal, process|
         
     | 
| 
      
 25 
     | 
    
         
            +
              #     puts "Sent #{signal} to #{process.pid}"
         
     | 
| 
      
 26 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 27 
     | 
    
         
            +
              #
         
     | 
| 
      
 28 
     | 
    
         
            +
              #   signaller.on_error do |e, signal, process|
         
     | 
| 
      
 29 
     | 
    
         
            +
              #     puts "Ooops, got #{e} sending #{signal} to #{process.pid}"
         
     | 
| 
      
 30 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 31 
     | 
    
         
            +
              # end
         
     | 
| 
      
 32 
     | 
    
         
            +
              #
         
     | 
| 
      
 33 
     | 
    
         
            +
              # signaller.send_signals
         
     | 
| 
      
 34 
     | 
    
         
            +
              #
         
     | 
| 
      
 35 
     | 
    
         
            +
              class ProcessSignaller
         
     | 
| 
      
 36 
     | 
    
         
            +
                extend Forwardable
         
     | 
| 
      
 37 
     | 
    
         
            +
                def_delegators :locator, :include, :exclude, :memory_greater_than,
         
     | 
| 
      
 38 
     | 
    
         
            +
                               :cpu_greater_than, :alive_longer_than, :filter
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                attr_reader :signal
         
     | 
| 
      
 41 
     | 
    
         
            +
                attr_writer :locator
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def initialize(&block)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @locator = ProcessLocator.new
         
     | 
| 
      
 45 
     | 
    
         
            +
                  on_no_processes {}
         
     | 
| 
      
 46 
     | 
    
         
            +
                  before_signal {}
         
     | 
| 
      
 47 
     | 
    
         
            +
                  after_signal {}
         
     | 
| 
      
 48 
     | 
    
         
            +
                  on_error {|e, process, signal| raise e}
         
     | 
| 
      
 49 
     | 
    
         
            +
                  block.call(self)
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                ##
         
     | 
| 
      
 53 
     | 
    
         
            +
                # Send the specified signal to all located processes
         
     | 
| 
      
 54 
     | 
    
         
            +
                def send_signals
         
     | 
| 
      
 55 
     | 
    
         
            +
                  processes = @locator.locate
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  if processes.empty?
         
     | 
| 
      
 58 
     | 
    
         
            +
                    @on_no_processes.call
         
     | 
| 
      
 59 
     | 
    
         
            +
                  else
         
     | 
| 
      
 60 
     | 
    
         
            +
                    processes.each do |process|
         
     | 
| 
      
 61 
     | 
    
         
            +
                      signal_process(process)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                rescue StandardError => e
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @on_error.call(e)
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                def signal(signal)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  @signal = Signal.list[signal.to_s.upcase].tap do |sig|
         
     | 
| 
      
 70 
     | 
    
         
            +
                    unless sig
         
     | 
| 
      
 71 
     | 
    
         
            +
                      raise "'#{signal}' not found -- see http://ruby-doc.org/core-1.8.7/Signal.html#method-c-list"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def locator(locator=nil)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  @locator ||= (locator || ProcessLocator.new)
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def on_no_processes(&callback)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  @on_no_processes = callback
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def before_signal(&callback)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  @before_signal = callback
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                def after_signal(&callback)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  @after_signal = callback
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def on_error(&callback)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  @on_error = callback
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                def target_parent(flag=false)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @target_parent = flag
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                private
         
     | 
| 
      
 101 
     | 
    
         
            +
                def signal_process(process)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  @before_signal.call(@signal, process)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  if @target_parent
         
     | 
| 
      
 104 
     | 
    
         
            +
                    Process.kill(@signal, process.ppid)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  else
         
     | 
| 
      
 106 
     | 
    
         
            +
                    Process.kill(@signal, process.pid)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  end
         
     | 
| 
      
 108 
     | 
    
         
            +
                  @after_signal.call(@signal, process)
         
     | 
| 
      
 109 
     | 
    
         
            +
                rescue StandardError => e
         
     | 
| 
      
 110 
     | 
    
         
            +
                  @on_error.call(e, @signal, process)
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
              end
         
     | 
| 
      
 113 
     | 
    
         
            +
            end
         
     | 
    
        data/snipr.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
            lib = File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'snipr/version'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.name          = "snipr"
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.version       = Snipr::VERSION
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.authors       = ["Lance Woodson"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.email         = ["lance@webmaneuvers.com"]
         
     | 
| 
      
 11 
     | 
    
         
            +
              spec.summary       = %q{Take aim and fire at runaway processes using ruby}
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.description   = <<-END
         
     | 
| 
      
 13 
     | 
    
         
            +
            Ruby classes and executables for targetting and sending signals to
         
     | 
| 
      
 14 
     | 
    
         
            +
            *nix processes that match/don't match command name patterns, memory
         
     | 
| 
      
 15 
     | 
    
         
            +
            use, cpu use and time alive
         
     | 
| 
      
 16 
     | 
    
         
            +
              END
         
     | 
| 
      
 17 
     | 
    
         
            +
              spec.homepage      = ""
         
     | 
| 
      
 18 
     | 
    
         
            +
              spec.license       = "MIT"
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              spec.files         = `git ls-files -z`.split("\x0")
         
     | 
| 
      
 21 
     | 
    
         
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         
     | 
| 
      
 22 
     | 
    
         
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         
     | 
| 
      
 23 
     | 
    
         
            +
              spec.require_paths = ["lib"]
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              spec.add_development_dependency "bundler", "~> 1.6"
         
     | 
| 
      
 26 
     | 
    
         
            +
              spec.add_development_dependency "rake", "~> 10.0"
         
     | 
| 
      
 27 
     | 
    
         
            +
              spec.add_development_dependency "rspec", "~> 3.1.0"
         
     | 
| 
      
 28 
     | 
    
         
            +
              spec.add_development_dependency "pry"
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,123 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Snipr
         
     | 
| 
      
 4 
     | 
    
         
            +
              describe ProcessLocator do
         
     | 
| 
      
 5 
     | 
    
         
            +
                describe "#parse_seconds" do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  let(:result) {subject.send(:parse_seconds, etime)}
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  describe "with a time spanning days" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    let(:etime) {"1-02:03:04"}
         
     | 
| 
      
 10 
     | 
    
         
            +
                    it "should calculate the correct number of seconds" do
         
     | 
| 
      
 11 
     | 
    
         
            +
                      expect(result).to eq(93784)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  describe "with a time spanning hours" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                    let(:etime) {"2:03:04"}
         
     | 
| 
      
 17 
     | 
    
         
            +
                    it "should calculate the correct number of seconds" do
         
     | 
| 
      
 18 
     | 
    
         
            +
                      expect(result).to eq(7384)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  describe "with a time spanning minutes" do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    let(:etime) {"03:04"}
         
     | 
| 
      
 24 
     | 
    
         
            +
                    it "should calculate the correct number of seconds" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                      expect(result).to eq(184)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  describe "with a time spanning seconds" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                    let(:etime) {"04"}
         
     | 
| 
      
 31 
     | 
    
         
            +
                    it "should calculate the correct number of seconds" do
         
     | 
| 
      
 32 
     | 
    
         
            +
                      expect(result).to eq(4)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                describe "#locate" do
         
     | 
| 
      
 38 
     | 
    
         
            +
                  let(:ps_output) {File.read("spec/ps_output.txt").split("\n")}
         
     | 
| 
      
 39 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 40 
     | 
    
         
            +
                    expect(Snipr).to receive(:exec_cmd).and_return(ps_output).at_least(:once)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  it "should return an array of KernelProcess objects" do
         
     | 
| 
      
 44 
     | 
    
         
            +
                    process = subject.locate.select{|process| process.pid == 3552}.first
         
     | 
| 
      
 45 
     | 
    
         
            +
                    expect(process.pid).to eq(3552)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    expect(process.ppid).to eq(4354)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    expect(process.memory).to eq(1297860)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    expect(process.cpu).to eq(8.7)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    expect(process.etime).to eq("1-07:12:08")
         
     | 
| 
      
 50 
     | 
    
         
            +
                    expect(process.seconds_alive).to eq(112328)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    expect(process.command).to eq("resque-1.24.1: Processing foo since 1410077129 [FooJob]")
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  describe "when no processes match filters" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                    it "should return an empty array" do
         
     | 
| 
      
 56 
     | 
    
         
            +
                      subject.include /thereisnoinputwiththisstring/
         
     | 
| 
      
 57 
     | 
    
         
            +
                      expect(subject.locate).to be_empty
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  describe "when a single include is specified" do
         
     | 
| 
      
 62 
     | 
    
         
            +
                    it "should return all processes that match the include pattern" do
         
     | 
| 
      
 63 
     | 
    
         
            +
                      subject.include /Processing/
         
     | 
| 
      
 64 
     | 
    
         
            +
                      expect(subject.locate.size).to eq(20)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  describe "when multiple includes are specified" do
         
     | 
| 
      
 69 
     | 
    
         
            +
                    it "should return all processses that match all include patterns" do
         
     | 
| 
      
 70 
     | 
    
         
            +
                      subject.include /Processing/
         
     | 
| 
      
 71 
     | 
    
         
            +
                      subject.include /Delayed Items/
         
     | 
| 
      
 72 
     | 
    
         
            +
                      expect(subject.locate.size).to eq(1)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  describe "when a single exclude is specified" do
         
     | 
| 
      
 77 
     | 
    
         
            +
                    it "should return all processes not matching the exclude pattern" do
         
     | 
| 
      
 78 
     | 
    
         
            +
                      subject.exclude /grep/
         
     | 
| 
      
 79 
     | 
    
         
            +
                      expect(subject.locate.size).to eq(52)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  describe "when multiple excludes are specified" do
         
     | 
| 
      
 84 
     | 
    
         
            +
                    it "should return all processes that don't match all exclude patterns" do
         
     | 
| 
      
 85 
     | 
    
         
            +
                      subject.exclude /grep/
         
     | 
| 
      
 86 
     | 
    
         
            +
                      subject.exclude /scheduler/
         
     | 
| 
      
 87 
     | 
    
         
            +
                      expect(subject.locate.size).to eq(51)
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  describe "when filtering processes by memory greater than" do
         
     | 
| 
      
 92 
     | 
    
         
            +
                    it "should return only processes using memory greater than the specified amount" do
         
     | 
| 
      
 93 
     | 
    
         
            +
                      subject.memory_greater_than(1000000000)
         
     | 
| 
      
 94 
     | 
    
         
            +
                      expect(subject.locate.size).to eq(1)
         
     | 
| 
      
 95 
     | 
    
         
            +
                      expect(subject.locate.first.pid).to eq(32178)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    end
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  describe "when filtering processes by cpu greater than" do
         
     | 
| 
      
 100 
     | 
    
         
            +
                    it "should return only processes using cpu greater than the specified amount" do
         
     | 
| 
      
 101 
     | 
    
         
            +
                      subject.cpu_greater_than(90.0)
         
     | 
| 
      
 102 
     | 
    
         
            +
                      expect(subject.locate.size).to eq(1)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      expect(subject.locate.first.pid).to eq(6337)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  describe "when filtering processes by alive longer than" do
         
     | 
| 
      
 108 
     | 
    
         
            +
                    it "should return only processes that have been alive longer than the specified amount" do
         
     | 
| 
      
 109 
     | 
    
         
            +
                      subject.alive_longer_than(31449600)
         
     | 
| 
      
 110 
     | 
    
         
            +
                      expect(subject.locate.size).to eq(1)
         
     | 
| 
      
 111 
     | 
    
         
            +
                      expect(subject.locate.first.pid).to eq(28309)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    end
         
     | 
| 
      
 113 
     | 
    
         
            +
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                  describe "when filtering by a custom filter" do
         
     | 
| 
      
 116 
     | 
    
         
            +
                    it "should return only processes that match the filter" do
         
     | 
| 
      
 117 
     | 
    
         
            +
                      subject.filter { |process| process.pid % 2 == 0 }
         
     | 
| 
      
 118 
     | 
    
         
            +
                      expect(subject.locate.size).to eq(24)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
                end
         
     | 
| 
      
 122 
     | 
    
         
            +
              end
         
     | 
| 
      
 123 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,100 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'ostruct'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Snipr
         
     | 
| 
      
 5 
     | 
    
         
            +
              describe ProcessSignaller do
         
     | 
| 
      
 6 
     | 
    
         
            +
                let(:signal) {Signal.list["USR1"]}
         
     | 
| 
      
 7 
     | 
    
         
            +
                let(:ps_output) {File.read("spec/ps_output.txt").split("\n")}
         
     | 
| 
      
 8 
     | 
    
         
            +
                let(:checkins) {OpenStruct.new}
         
     | 
| 
      
 9 
     | 
    
         
            +
                subject do
         
     | 
| 
      
 10 
     | 
    
         
            +
                  ProcessSignaller.new do |signaller|
         
     | 
| 
      
 11 
     | 
    
         
            +
                    signaller.include /resque/i
         
     | 
| 
      
 12 
     | 
    
         
            +
                    signaller.signal  "USR1"
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    signaller.on_no_processes do
         
     | 
| 
      
 15 
     | 
    
         
            +
                      checkins.on_no_processes = true
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    signaller.before_signal do |signal, process|
         
     | 
| 
      
 19 
     | 
    
         
            +
                      checkins.before_signal = "#{signal} > #{process.pid}"
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    signaller.after_signal do |signal, process|
         
     | 
| 
      
 23 
     | 
    
         
            +
                      checkins.after_signal = "#{signal} > #{process.pid}"
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    signaller.on_error do |exc, signal, process|
         
     | 
| 
      
 27 
     | 
    
         
            +
                      msg = "#{exc}"
         
     | 
| 
      
 28 
     | 
    
         
            +
                      if signal && process
         
     | 
| 
      
 29 
     | 
    
         
            +
                        msg += " #{signal} > #{process.pid}"
         
     | 
| 
      
 30 
     | 
    
         
            +
                      end
         
     | 
| 
      
 31 
     | 
    
         
            +
                      checkins.on_error = msg
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                describe "#signal" do
         
     | 
| 
      
 37 
     | 
    
         
            +
                  it "should raise an error if the signal is not defined by the system" do
         
     | 
| 
      
 38 
     | 
    
         
            +
                    expect{subject.signal("AJDKASDJKLASD")}.to raise_error
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  it "should assign the numeric value of the signal as defined by the system" do
         
     | 
| 
      
 42 
     | 
    
         
            +
                    expect(subject.signal("USR1")).to eq(Signal.list["USR1"])
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                describe "#signal" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                  context "when there is a general failure" do
         
     | 
| 
      
 48 
     | 
    
         
            +
                    let(:locator) {subject.instance_variable_get(:@locator)}
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    it "should invoke the on_error callback" do
         
     | 
| 
      
 51 
     | 
    
         
            +
                      expect(locator).to receive(:locate).and_raise('Ouch!')
         
     | 
| 
      
 52 
     | 
    
         
            +
                      subject.send_signals
         
     | 
| 
      
 53 
     | 
    
         
            +
                      expect(checkins.on_error).to eq("Ouch!")
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  context "when no processes found" do
         
     | 
| 
      
 58 
     | 
    
         
            +
                    before {subject.exclude /resque/i}
         
     | 
| 
      
 59 
     | 
    
         
            +
                    it "should invoke the on_no_processes callback" do
         
     | 
| 
      
 60 
     | 
    
         
            +
                      subject.send_signals
         
     | 
| 
      
 61 
     | 
    
         
            +
                      expect(checkins.on_no_processes).to be_truthy
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  context "when process is found" do
         
     | 
| 
      
 66 
     | 
    
         
            +
                    before do
         
     | 
| 
      
 67 
     | 
    
         
            +
                      expect(Snipr).to receive(:exec_cmd).and_return(ps_output).at_least(:once)
         
     | 
| 
      
 68 
     | 
    
         
            +
                      subject.cpu_greater_than(90)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    context "targetting the process itself" do
         
     | 
| 
      
 72 
     | 
    
         
            +
                      it "should send the appropriate signal to the process and call callbacks" do
         
     | 
| 
      
 73 
     | 
    
         
            +
                        expect(Process).to receive(:kill).with(signal, 6337)
         
     | 
| 
      
 74 
     | 
    
         
            +
                        subject.send_signals
         
     | 
| 
      
 75 
     | 
    
         
            +
                        expect(checkins.before_signal).to eq("#{signal} > 6337")
         
     | 
| 
      
 76 
     | 
    
         
            +
                        expect(checkins.after_signal).to eq("#{signal} > 6337")
         
     | 
| 
      
 77 
     | 
    
         
            +
                      end
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
                    
         
     | 
| 
      
 80 
     | 
    
         
            +
                    context "targetting the parent process" do
         
     | 
| 
      
 81 
     | 
    
         
            +
                      it "should send the appropriate signal to the parent process and call callbacks" do
         
     | 
| 
      
 82 
     | 
    
         
            +
                        subject.target_parent true
         
     | 
| 
      
 83 
     | 
    
         
            +
                        expect(Process).to receive(:kill).with(signal, 4347)
         
     | 
| 
      
 84 
     | 
    
         
            +
                        subject.send_signals
         
     | 
| 
      
 85 
     | 
    
         
            +
                        expect(checkins.before_signal).to eq("#{signal} > 6337")
         
     | 
| 
      
 86 
     | 
    
         
            +
                        expect(checkins.after_signal).to eq("#{signal} > 6337")
         
     | 
| 
      
 87 
     | 
    
         
            +
                      end
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                    context "when encountering an error signalling a process" do
         
     | 
| 
      
 91 
     | 
    
         
            +
                      it "should call the on_error callback" do
         
     | 
| 
      
 92 
     | 
    
         
            +
                        expect(Process).to receive(:kill).with(signal, 6337).and_raise('Ouch!')
         
     | 
| 
      
 93 
     | 
    
         
            +
                        subject.send_signals
         
     | 
| 
      
 94 
     | 
    
         
            +
                        expect(checkins.on_error).to eq("Ouch! #{signal} > 6337")
         
     | 
| 
      
 95 
     | 
    
         
            +
                      end
         
     | 
| 
      
 96 
     | 
    
         
            +
                    end
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
              end
         
     | 
| 
      
 100 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/ps_output.txt
    ADDED
    
    | 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             3552  4354 1297860 8.7 1-07:12:08 resque-1.24.1: Processing foo since 1410077129 [FooJob]
         
     | 
| 
      
 2 
     | 
    
         
            +
             4236     1 1169412 0.0 3-12:52:29 resque-1.24.1: Waiting for bar,bar
         
     | 
| 
      
 3 
     | 
    
         
            +
             4238     1 1191864 0.0 3-12:52:29 resque-1.24.1: Waiting for foo,bar
         
     | 
| 
      
 4 
     | 
    
         
            +
             4241     1 1192064 0.0 3-12:52:29 resque-1.24.1: Waiting for foo,bar
         
     | 
| 
      
 5 
     | 
    
         
            +
             4245     1 1184716 0.2 3-12:52:29 resque-1.24.1: Forked 28309 at 1410084369
         
     | 
| 
      
 6 
     | 
    
         
            +
             4248     1 1206600 0.3 3-12:52:29 resque-1.24.1: Forked 28778 at 1410189413
         
     | 
| 
      
 7 
     | 
    
         
            +
             4250     1 1198872 0.2 3-12:52:29 resque-1.24.1: Forked 32153 at 1410189457
         
     | 
| 
      
 8 
     | 
    
         
            +
             4253     1 1202312 0.3 3-12:52:29 resque-1.24.1: Forked 31818 at 1410189453
         
     | 
| 
      
 9 
     | 
    
         
            +
             4257     1 1194072 0.4 3-12:52:29 resque-1.24.1: Forked 17477 at 1410188882
         
     | 
| 
      
 10 
     | 
    
         
            +
             4259     1 1188480 0.0 3-12:52:29 resque-1.24.1: Waiting for foo,bar
         
     | 
| 
      
 11 
     | 
    
         
            +
             4263     1 1188872 0.0 3-12:52:29 resque-1.24.1: Waiting for foo,bar
         
     | 
| 
      
 12 
     | 
    
         
            +
             4265     1 1189032 0.0 3-12:52:29 resque-1.24.1: Waiting for foo,bar
         
     | 
| 
      
 13 
     | 
    
         
            +
             4269     1 1182676 0.1 3-12:52:29 resque-1.24.1: Forked 29640 at 1410189424
         
     | 
| 
      
 14 
     | 
    
         
            +
             4271     1 1195432 0.2 3-12:52:29 resque-1.24.1: Forked 32035 at 1410189455
         
     | 
| 
      
 15 
     | 
    
         
            +
             4274     1 1181816 0.1 3-12:52:29 resque-1.24.1: Forked 31915 at 1410189454
         
     | 
| 
      
 16 
     | 
    
         
            +
             4277     1 1188152 0.1 3-12:52:28 resque-1.24.1: Forked 32038 at 1410189455
         
     | 
| 
      
 17 
     | 
    
         
            +
             4280     1 1179444 0.1 3-12:52:28 resque-1.24.1: Forked 30789 at 1410185297
         
     | 
| 
      
 18 
     | 
    
         
            +
             4284     1 1169100 0.0 3-12:52:28 resque-1.24.1: Waiting for baz
         
     | 
| 
      
 19 
     | 
    
         
            +
             4293     1 1183856 0.0 3-12:52:28 resque-1.24.1: Waiting for baz
         
     | 
| 
      
 20 
     | 
    
         
            +
             4301     1 1170028 0.0 3-12:52:28 resque-1.24.1: Waiting for baz
         
     | 
| 
      
 21 
     | 
    
         
            +
             4309     1 1155112 0.0 3-12:52:28 resque-1.24.1: Waiting for baz
         
     | 
| 
      
 22 
     | 
    
         
            +
             4316     1 1188900 0.0 3-12:52:28 resque-1.24.1: Waiting for baz
         
     | 
| 
      
 23 
     | 
    
         
            +
             4321     1 1196844 0.3 3-12:52:28 resque-1.24.1: Forked 7229 at 1410131675
         
     | 
| 
      
 24 
     | 
    
         
            +
             4324     1 1157052 0.3 3-12:52:28 resque-1.24.1: Forked 28474 at 1410189411
         
     | 
| 
      
 25 
     | 
    
         
            +
             4326     1 1179852 0.1 3-12:52:28 resque-1.24.1: Forked 27462 at 1410189396
         
     | 
| 
      
 26 
     | 
    
         
            +
             4337     1 1202044 0.3 3-12:52:28 resque-1.24.1: Forked 32178 at 1410189457
         
     | 
| 
      
 27 
     | 
    
         
            +
             4340     1 1202976 0.3 3-12:52:27 resque-1.24.1: Forked 31662 at 1410189012
         
     | 
| 
      
 28 
     | 
    
         
            +
             4347     1 1163824 0.4 3-12:52:27 resque-1.24.1: Forked 6337 at 1410189132
         
     | 
| 
      
 29 
     | 
    
         
            +
             4351     1 1163120 0.2 3-12:52:27 resque-1.24.1: Forked 22400 at 1410189331
         
     | 
| 
      
 30 
     | 
    
         
            +
             4354     1 1196480 0.2 3-12:52:27 resque-1.24.1: Forked 3552 at 1410077129
         
     | 
| 
      
 31 
     | 
    
         
            +
             4357     1 1163572 0.3 3-12:52:27 resque-1.24.1: Forked 8356 at 1410189171
         
     | 
| 
      
 32 
     | 
    
         
            +
             4361     1 1187620 0.0 3-12:52:27 resque-1.24.1: Waiting for foo
         
     | 
| 
      
 33 
     | 
    
         
            +
             4364     1 1169364 0.0 3-12:52:27 resque-1.24.1: Waiting for bar
         
     | 
| 
      
 34 
     | 
    
         
            +
             5585     1 972188 0.0  3-12:50:57 resque-scheduler-2.0.1: Processing Delayed Items                       
         
     | 
| 
      
 35 
     | 
    
         
            +
             6337  4347 1293004 99.9      05:26 resque-1.24.1: Processing foo since 1410189132 [FooJob]
         
     | 
| 
      
 36 
     | 
    
         
            +
             7229  4321 1292692 8.2   16:03:03 resque-1.24.1: Processing foo since 1410131675 [FooJob]
         
     | 
| 
      
 37 
     | 
    
         
            +
             8356  4357 1220988 19.0     04:47 resque-1.24.1: Processing foo since 1410189171 [FooJob]
         
     | 
| 
      
 38 
     | 
    
         
            +
            17477  4257 1194072 0.0      09:35 resque-1.24.1: Processing foo since 1410188882 [FooJob]
         
     | 
| 
      
 39 
     | 
    
         
            +
            22400  4351 1219712 3.3      02:06 resque-1.24.1: Processing foo since 1410189331 [FooJob]
         
     | 
| 
      
 40 
     | 
    
         
            +
            27462  4326 1194624 2.1      01:02 resque-1.24.1: Processing foo since 1410189396 [FooJob]
         
     | 
| 
      
 41 
     | 
    
         
            +
            28309  4245 1278328 7.1 364-05:11:28 resque-1.24.1: Processing foo since 1410084369 [FooJob]
         
     | 
| 
      
 42 
     | 
    
         
            +
            28474  4324 1182012 6.7      00:47 resque-1.24.1: Processing foo since 1410189410 [FooJob]
         
     | 
| 
      
 43 
     | 
    
         
            +
            28778  4248 1205572 4.9      00:45 resque-1.24.1: Processing foo since 1410189413 [FooJob]
         
     | 
| 
      
 44 
     | 
    
         
            +
            29640  4269 1189152 3.2      00:34 resque-1.24.1: Processing foo since 1410189424 [FooJob]
         
     | 
| 
      
 45 
     | 
    
         
            +
            30789  4280 1263476 6.7   01:09:21 resque-1.24.1: Processing foo since 1410185297 [FooJob]
         
     | 
| 
      
 46 
     | 
    
         
            +
            31662  4340 1286344 2.7      07:26 resque-1.24.1: Processing foo since 1410189012 [FooJob]
         
     | 
| 
      
 47 
     | 
    
         
            +
            31818  4253 1202312 4.6      00:05 resque-1.24.1: Processing foo since 1410189452 [FooJob]
         
     | 
| 
      
 48 
     | 
    
         
            +
            31915  4274 1181816 13.2     00:04 resque-1.24.1: Processing foo since 1410189454 [FooJob]
         
     | 
| 
      
 49 
     | 
    
         
            +
            32035  4271 1195432 13.5     00:02 resque-1.24.1: Processing foo since 1410189455 [FooJob]
         
     | 
| 
      
 50 
     | 
    
         
            +
            32038  4277 1188152 13.0     00:02 resque-1.24.1: Processing foo since 1410189455 [FooJob]
         
     | 
| 
      
 51 
     | 
    
         
            +
            32153  4250 1198872 21.0     00:01 resque-1.24.1: Processing foo since 1410189457 [FooJob]
         
     | 
| 
      
 52 
     | 
    
         
            +
            32178  4337 1001202048 0.0      00:00 resque-1.24.1: Processing bar since 1410189457 [BarJob]
         
     | 
| 
      
 53 
     | 
    
         
            +
            32189 28509   276  0.0       00:00 grep resque
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,114 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: snipr
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.1
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Lance Woodson
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2014-09-08 00:00:00 Z
         
     | 
| 
      
 13 
     | 
    
         
            +
            dependencies: 
         
     | 
| 
      
 14 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 15 
     | 
    
         
            +
              name: bundler
         
     | 
| 
      
 16 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 17 
     | 
    
         
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 18 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 19 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 20 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 21 
     | 
    
         
            +
                    version: "1.6"
         
     | 
| 
      
 22 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 23 
     | 
    
         
            +
              version_requirements: *id001
         
     | 
| 
      
 24 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 25 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 26 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 27 
     | 
    
         
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 28 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 29 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 30 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 31 
     | 
    
         
            +
                    version: "10.0"
         
     | 
| 
      
 32 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 33 
     | 
    
         
            +
              version_requirements: *id002
         
     | 
| 
      
 34 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 35 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 36 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 37 
     | 
    
         
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 38 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 39 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 40 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 41 
     | 
    
         
            +
                    version: 3.1.0
         
     | 
| 
      
 42 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 43 
     | 
    
         
            +
              version_requirements: *id003
         
     | 
| 
      
 44 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 45 
     | 
    
         
            +
              name: pry
         
     | 
| 
      
 46 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 47 
     | 
    
         
            +
              requirement: &id004 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 48 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 49 
     | 
    
         
            +
                - &id005 
         
     | 
| 
      
 50 
     | 
    
         
            +
                  - ">="
         
     | 
| 
      
 51 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 52 
     | 
    
         
            +
                    version: "0"
         
     | 
| 
      
 53 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 54 
     | 
    
         
            +
              version_requirements: *id004
         
     | 
| 
      
 55 
     | 
    
         
            +
            description: |
         
     | 
| 
      
 56 
     | 
    
         
            +
              Ruby classes and executables for targetting and sending signals to
         
     | 
| 
      
 57 
     | 
    
         
            +
              *nix processes that match/don't match command name patterns, memory
         
     | 
| 
      
 58 
     | 
    
         
            +
              use, cpu use and time alive
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            email: 
         
     | 
| 
      
 61 
     | 
    
         
            +
            - lance@webmaneuvers.com
         
     | 
| 
      
 62 
     | 
    
         
            +
            executables: 
         
     | 
| 
      
 63 
     | 
    
         
            +
            - reap_resque_workers
         
     | 
| 
      
 64 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 69 
     | 
    
         
            +
            - .gitignore
         
     | 
| 
      
 70 
     | 
    
         
            +
            - .ruby-gemset
         
     | 
| 
      
 71 
     | 
    
         
            +
            - .ruby-version
         
     | 
| 
      
 72 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 73 
     | 
    
         
            +
            - LICENSE.txt
         
     | 
| 
      
 74 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 75 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 76 
     | 
    
         
            +
            - bin/reap_resque_workers
         
     | 
| 
      
 77 
     | 
    
         
            +
            - lib/snipr.rb
         
     | 
| 
      
 78 
     | 
    
         
            +
            - lib/snipr/output.rb
         
     | 
| 
      
 79 
     | 
    
         
            +
            - lib/snipr/process_locator.rb
         
     | 
| 
      
 80 
     | 
    
         
            +
            - lib/snipr/process_signaller.rb
         
     | 
| 
      
 81 
     | 
    
         
            +
            - lib/snipr/version.rb
         
     | 
| 
      
 82 
     | 
    
         
            +
            - snipr.gemspec
         
     | 
| 
      
 83 
     | 
    
         
            +
            - spec/process_locator_spec.rb
         
     | 
| 
      
 84 
     | 
    
         
            +
            - spec/process_signaller_spec.rb
         
     | 
| 
      
 85 
     | 
    
         
            +
            - spec/ps_output.txt
         
     | 
| 
      
 86 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 87 
     | 
    
         
            +
            homepage: ""
         
     | 
| 
      
 88 
     | 
    
         
            +
            licenses: 
         
     | 
| 
      
 89 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 90 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 93 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 96 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 97 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 98 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 99 
     | 
    
         
            +
              - *id005
         
     | 
| 
      
 100 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 101 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 102 
     | 
    
         
            +
              - *id005
         
     | 
| 
      
 103 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 106 
     | 
    
         
            +
            rubygems_version: 2.0.14
         
     | 
| 
      
 107 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 108 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 109 
     | 
    
         
            +
            summary: Take aim and fire at runaway processes using ruby
         
     | 
| 
      
 110 
     | 
    
         
            +
            test_files: 
         
     | 
| 
      
 111 
     | 
    
         
            +
            - spec/process_locator_spec.rb
         
     | 
| 
      
 112 
     | 
    
         
            +
            - spec/process_signaller_spec.rb
         
     | 
| 
      
 113 
     | 
    
         
            +
            - spec/ps_output.txt
         
     | 
| 
      
 114 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     |