This repository has been archived by the owner on May 17, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathwith_retry.rb
executable file
·88 lines (76 loc) · 2.34 KB
/
with_retry.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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