Created
September 16, 2017 07:19
-
-
Save mexisme/d72addcb0d4d7cdd37b88d645b9699f8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note: Updated from https://github.com/mexisme/spigot-docker/blob/master/lib/myshell.rb | |
# If your prefer the 'logging' gem: | |
# LOG = Logging.logger(STDOUT) | |
LOG = Logger.new(STDOUT) | |
require 'benchmark' | |
require 'timeout' | |
class MyShell | |
class Logged | |
def self.run(*args) | |
self.new(*args).call | |
end | |
attr_reader :cmd, :args | |
def initialize(cmd, *args) | |
@cmd = cmd | |
@args = args | |
end | |
def to_s | |
([cmd] + args).join(' ') | |
end | |
def inspect | |
to_s.inspect | |
end | |
def call | |
LOG.debug "Running #{inspect}" | |
Rake.sh cmd, *args | |
end | |
alias :sh :call | |
end | |
class Interruptible < Logged | |
class Interrupted < RuntimeError; end | |
KILL_TIMEOUT = 30 | |
def call | |
status = nil | |
pid = Process.spawn(cmd, *args) | |
LOG.debug "Started #{cmd.inspect} with PID #{pid}." | |
begin | |
Signal.trap('INT') { raise Interrupted } | |
_, status = yield(self, pid) if block_given? | |
rescue Interrupted | |
Signal.trap('INT', 'DEFAULT') | |
raise | |
rescue => e | |
LOG.warn "An exception (#{e.inspect}) was raised while running #{cmd.inspect}." | |
end | |
LOG.error "#{cmd.inspect} failed with exit-code #{status}." if status && !status.success? | |
ensure | |
cleanup(pid) | |
end | |
def cleanup(pid) | |
catch(:done) do | |
# Step through a list of signal-types to kill the subprocess, until we kill it: | |
# TODO: Should we KILL ? | |
%w[INT TERM KILL KILL].each do |signal| | |
begin | |
LOG.debug "Sending #{signal.inspect} to #{cmd.inspect} (PID #{pid})." | |
Process.kill(signal, pid) | |
LOG.debug "Will wait #{KILL_TIMEOUT} sec for death..." | |
Timeout.timeout(KILL_TIMEOUT) do | |
Process.waitpid(pid) | |
throw :done | |
end | |
rescue Timeout::Error | |
LOG.debug "#{cmd.inspect} (PID #{pid}) didn't die within #{KILL_TIMEOUT} sec" | |
rescue SystemCallError | |
LOG.debug "PID #{pid} already gone..." | |
throw :done | |
end | |
end | |
fail "Could not kill PID #{pid}!" | |
end | |
end | |
end | |
class Benchmarked < Logged | |
def self.collected | |
@collected ||= [] | |
end | |
def self.show_collected | |
collected.each do |sh| | |
elapsed = Time.at(sh.benchmark.real).utc.strftime("%-Hhr %-Mmin %-Ssec") | |
LOG.info "#{sh.benchmark.label} took #{elapsed}" | |
end | |
end | |
##### | |
attr_reader :benchmark | |
def initialize(*args) | |
super | |
end | |
def call | |
@benchmark = Benchmark.measure(inspect) { super } | |
self.class.collected << self | |
@benchmark | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment