Skip to content
This repository has been archived by the owner on May 17, 2019. It is now read-only.

Commit

Permalink
Create with_retry.rb
Browse files Browse the repository at this point in the history
  • Loading branch information
eeue56 committed Mar 14, 2016
1 parent dc40f81 commit 8a07f12
Showing 1 changed file with 88 additions and 0 deletions.
88 changes: 88 additions & 0 deletions with_retry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env ruby

require 'English'
require 'pty'

=begin
Runs package install until it succeeds or fails 10 times in a row.
Test cases for testing manually:
# fails permanently
$ ./with_retry.rb ruby -e 'raise "Hello"'
$ ./with_retry.rb ruby -e 'exit 2'
# command not found
$ ./with_retry.rb non-existent-command
# succeeds
$ ./with_retry.rb ruby -e 'exit 0'
$ ./with_retry.rb ruby -e 'sleep(1); now = `date +%s`.to_i; goal = ARGV[0].to_i + 5; puts "#{now} > #{goal}"; exit (now > goal)' `date +%s`
=end

def run_command_with_retry(command_and_args)
exit_status = nil
last_exception = nil
10.times do |i|
begin
last_exception, exit_status = run_command command_and_args
exit 0 if exit_status == 0
rescue Errno::ENOENT
puts "#{command_and_args.first}: command not found"
exit 1
rescue => e
exit_status = e
end
puts "Attempt ##{i} failure: #{exit_status.class}:\n#{exit_status}"
end

puts "Permanently failed to execute: #{command_and_args.join(' ')}"
puts "Last exception from #run_command was: \n #{last_exception.class}: #{last_exception}" if last_exception
exit 1
end

def run_command(command_and_args)
last_exception = nil
status = nil

begin
PTY.spawn(*command_and_args) do |stdout, _stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO => e
# Errno:EIO error, but this probably just means
# that the process has finished giving output
last_exception = e
ensure
# ref:
# http://stackoverflow.com/a/10306782/20226
# http://stackoverflow.com/a/7263243/20226
_pid, status = Process.wait2 pid
end
end

# ref:
# http://www.shanison.com/2010/09/11/ptychildexited-exception-and-ptys-exit-status/
if status.nil?
status = if $ERROR_INFO.nil? || $ERROR_INFO.is_a?(SystemExit) && $ERROR_INFO.success?
0
else
$ERROR_INFO.is_a?(SystemExit) ? $ERROR_INFO.status.exitstatus : 1
end
end
rescue PTY::ChildExited => e
# The child process exited
last_exception = e
status = e.status
end
[last_exception, status]
end

if __FILE__ == $PROGRAM_NAME
if ARGV.length > 0
run_command_with_retry ARGV
else
puts "Usage: with_retry.rb command --and your --args of choice"
exit 1
end
end

0 comments on commit 8a07f12

Please sign in to comment.