immortalize 0.1.1 → 0.1.2
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.
- data/VERSION +1 -1
- data/bin/immortalize +103 -18
- data/immortalize.gemspec +2 -2
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/bin/immortalize
CHANGED
@@ -20,7 +20,7 @@ require 'merb-core'
|
|
20
20
|
require 'merb-mailer'
|
21
21
|
Merb::Mailer.delivery_method = :sendmail
|
22
22
|
|
23
|
-
$log_location = "
|
23
|
+
$log_location = "#{ENV['HOME']}/.immortalize"
|
24
24
|
`mkdir -p "#{$log_location}"` unless File.directory?($log_location)
|
25
25
|
$registry_filename = "#{$log_location}/registry.yaml"
|
26
26
|
File.open($registry_filename, 'w'){|f| f << {}.to_yaml} unless File.exists?($registry_filename)
|
@@ -40,17 +40,22 @@ To remove a command:
|
|
40
40
|
To inspect the current list of immortal commands:
|
41
41
|
#{$0} list
|
42
42
|
|
43
|
+
To install the immortalize cron job (which does the actual work):
|
44
|
+
immortalize setup
|
45
|
+
|
43
46
|
Run this command with no arguments as a cron job, to run every minute:
|
44
47
|
* * * * * immortalize
|
48
|
+
|
49
|
+
Options:
|
45
50
|
ENDBANNER
|
46
51
|
|
47
|
-
|
48
|
-
opts.on( '--
|
52
|
+
$options[:notification_recipient] = nil
|
53
|
+
opts.on( '--notify=EMAIL', "The email address to which failure notifications should be sent." ) do |email|
|
49
54
|
$options[:notification_recipient] = email
|
50
55
|
end
|
51
56
|
|
52
57
|
$options[:max_failures] = 5
|
53
|
-
opts.on('--max_failures=
|
58
|
+
opts.on('--max_failures=NUM', "Notify on NUM or more failures within an hour (default 5)") do |num|
|
54
59
|
$options[:max_failures] = num.to_i
|
55
60
|
end
|
56
61
|
|
@@ -80,6 +85,16 @@ class Time
|
|
80
85
|
end
|
81
86
|
|
82
87
|
class Immortal
|
88
|
+
def self.new(identifier)
|
89
|
+
if $registry[identifier]
|
90
|
+
obj = allocate
|
91
|
+
obj.send :initialize, identifier
|
92
|
+
obj
|
93
|
+
else
|
94
|
+
puts "tried:\n\t#{identifier}commands:\n\t#{$registry.values.map {|r| r[:command]}.join("\n\t")}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
83
98
|
attr_reader :identifier
|
84
99
|
def initialize(identifier)
|
85
100
|
@identifier = identifier
|
@@ -101,13 +116,23 @@ class Immortal
|
|
101
116
|
def start!
|
102
117
|
# Run the command and gather the pid
|
103
118
|
pid = nil
|
104
|
-
open("
|
119
|
+
open("|echo \"#{@reg[:command]}\" | sh & echo $!") do |f|
|
105
120
|
pid = f.sysread(5).chomp.to_i
|
106
121
|
end
|
107
122
|
# Log the pid
|
108
123
|
puts "pid #{pid}"
|
109
124
|
$registry[identifier][:pid] = pid
|
110
125
|
end
|
126
|
+
def stop!
|
127
|
+
if running?
|
128
|
+
pid = $registry[identifier].delete(:pid)
|
129
|
+
`kill -INT #{pid}`
|
130
|
+
puts "attempted to kill pid #{pid}: \"#{@reg[:command]}\""
|
131
|
+
else
|
132
|
+
warn "\"#{@reg[:command]}\" not running!"
|
133
|
+
false
|
134
|
+
end
|
135
|
+
end
|
111
136
|
|
112
137
|
def failed!
|
113
138
|
failures << Time.now
|
@@ -137,25 +162,78 @@ class Immortal
|
|
137
162
|
end
|
138
163
|
end
|
139
164
|
|
165
|
+
# Curate the command string
|
166
|
+
if ARGV[1].to_s.length > 1 && ARGV[1] !~ /^\d+$/
|
167
|
+
puts ARGV.inspect
|
168
|
+
$command_string = ARGV[1]
|
169
|
+
# Complain about the string if it does not have proper output redirections
|
170
|
+
cmds = $command_string.split(/; ?/)
|
171
|
+
last_cmd = cmds.pop
|
172
|
+
lst,out_s = last_cmd.split(/(?: \d)? ?>/,2)
|
173
|
+
cmds << lst
|
174
|
+
outs = last_cmd.scan(/(?: \d)? ?> ?\S+/)
|
175
|
+
outs = outs.map {|o| o.sub(/ ?> ?/,">").sub(/^>/,"1>") }
|
176
|
+
unless outs.any? {|o| o =~ /^2>/}
|
177
|
+
warn "Appending default STDERR redirection: 2>&1 (STDERR > STDOUT)"
|
178
|
+
outs << "2>&1"
|
179
|
+
end
|
180
|
+
unless outs.any? {|o| o =~ /^1?>/}
|
181
|
+
warn "#{$command_string}\nInvalid command: You need to add proper STDOUT redirection, ex: > /dev/null or 1>log/run.log or 1 > log/run.log"
|
182
|
+
exit
|
183
|
+
end
|
184
|
+
$command_string = cmds.join('; ') + ' ' + outs.join(' ')
|
185
|
+
end
|
186
|
+
|
187
|
+
|
140
188
|
# Main logic
|
141
189
|
unless ::Object.const_defined?(:IRB)
|
142
190
|
case $action
|
191
|
+
when 'setup'
|
192
|
+
crons = `crontab -l 2>/dev/null`.split(/\n/)
|
193
|
+
immortalize_cmd = `which immortalize`.chomp
|
194
|
+
if immortalize_cmd.empty?
|
195
|
+
warn "Couldn't find installed version of the 'immortalize' command! (Try `which immortalize`)"
|
196
|
+
exit
|
197
|
+
end
|
198
|
+
crons.reject! {|c| c =~ /immortalize > #{$log_location}\/cron.log$/}
|
199
|
+
crons << "* * * * * #{immortalize_cmd} > #{$log_location}/cron.log\n"
|
200
|
+
puts "Installing crons:\n\t#{crons.join("\n\t")}"
|
201
|
+
f = IO.popen("crontab -", 'w')
|
202
|
+
f << crons.join("\n")
|
203
|
+
f.close
|
204
|
+
crons = `crontab -l 2>/dev/null`.split(/\n/)
|
205
|
+
puts "Installed crons:\n\t#{crons.join("\n\t")}"
|
143
206
|
when 'list'
|
144
|
-
puts $registry.inspect
|
207
|
+
# puts $registry.inspect
|
145
208
|
puts "Immortalized:"
|
146
|
-
$registry.
|
147
|
-
|
209
|
+
keys = $registry.keys.sort
|
210
|
+
keys.each_with_index do |identifier,i|
|
211
|
+
puts "\t#{i+1}) " + Immortal.new(identifier).inspect
|
148
212
|
end
|
213
|
+
puts "\nTo remove jobs, for example job #1, from this list, run `immortalize remove 1`"
|
149
214
|
exit
|
150
215
|
|
216
|
+
when 'stop'
|
217
|
+
if ARGV[1] =~ /^\d+$/
|
218
|
+
identifier = $registry.keys.sort[ARGV[1].to_i-1]
|
219
|
+
else
|
220
|
+
identifier = SHA1.hexdigest($command_string)
|
221
|
+
end
|
222
|
+
immortal = Immortal.new(identifier)
|
223
|
+
immortal.stop!
|
224
|
+
|
151
225
|
when 'run'
|
226
|
+
if $options[:notification_recipient].nil?
|
227
|
+
warn "Must include --notify EMAIL_ADDRESS when adding a command!"
|
228
|
+
exit
|
229
|
+
end
|
230
|
+
|
152
231
|
# Running with a given command.
|
153
|
-
|
154
|
-
identifier = SHA1.hexdigest(command_string)
|
232
|
+
identifier = SHA1.hexdigest($command_string)
|
155
233
|
|
156
234
|
# Create the command
|
157
235
|
$registry[identifier] ||= {
|
158
|
-
:command => command_string
|
236
|
+
:command => $command_string
|
159
237
|
}
|
160
238
|
$registry[identifier].merge!($options)
|
161
239
|
|
@@ -169,32 +247,39 @@ unless ::Object.const_defined?(:IRB)
|
|
169
247
|
end
|
170
248
|
|
171
249
|
when 'remove'
|
172
|
-
|
173
|
-
|
174
|
-
|
250
|
+
if ARGV[1] =~ /^\d+$/
|
251
|
+
identifier = $registry.keys.sort[ARGV[1].to_i-1]
|
252
|
+
else
|
253
|
+
identifier = SHA1.hexdigest($command_string)
|
254
|
+
end
|
255
|
+
reg = $registry.delete(identifier)
|
256
|
+
puts "Deleted #{identifier}: \"#{reg[:command]}\""
|
175
257
|
|
176
258
|
when nil
|
177
259
|
# Running bare from cron.
|
178
260
|
# Check all logged commands with pids.
|
179
|
-
$registry.
|
261
|
+
puts "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] #{$registry.length} jobs"
|
262
|
+
$registry.keys.sort.each_with_index do |identifier,i|
|
180
263
|
immortal = Immortal.new(identifier)
|
181
264
|
|
182
265
|
# Check if running
|
183
266
|
if immortal.running?
|
184
|
-
puts "`#{immortal[:command]}' is running fine..."
|
267
|
+
# puts " #{i+1}) `#{immortal[:command]}' is running fine..."
|
185
268
|
else
|
186
|
-
puts "`#{immortal[:command]}' HAS DIED! Reviving..."
|
269
|
+
puts " #{i+1}) `#{immortal[:command]}' HAS DIED! Reviving..."
|
187
270
|
# Mark the failure
|
188
271
|
immortal.failed!
|
189
272
|
# Notify if failures have been frequent
|
190
273
|
if immortal.frequent_failures?
|
191
|
-
puts "
|
274
|
+
puts " #{i+1}) FREQUENT FAILURE ON #{identifier} (`#{immortal[:command]}')"
|
192
275
|
notify(immortal, "ImmortalCommand failure!\n\nCommand `#{immortal[:command]}' failed, threshold is #{immortal[:max_failures]} / hour.\n\n#{immortal.failures_today.size} failures so far today, #{immortal.failures_this_hour.size} in the past hour.")
|
193
276
|
end
|
194
277
|
# Start it
|
195
278
|
immortal.start!
|
196
279
|
end
|
197
280
|
end
|
281
|
+
else
|
282
|
+
puts optparse
|
198
283
|
end
|
199
284
|
end
|
200
285
|
|
data/immortalize.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{immortalize}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["BehindLogic"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-17}
|
13
13
|
s.default_executable = %q{immortalize}
|
14
14
|
s.description = %q{Watch a specific process, restart it if it dies.}
|
15
15
|
s.email = %q{gems@behindlogic.com}
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- BehindLogic
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-17 00:00:00 -04:00
|
18
18
|
default_executable: immortalize
|
19
19
|
dependencies: []
|
20
20
|
|