I've noticed that stderr from the child process and and restarter
stdout can get blended here, which is slightly surprising since
restarter waits until the child process has exited, i.e. it has closed
its file descriptors.
An example:
/app/scheduling/dispatcher.rb:56:in `block in start_strand'{"restarter":{"start_time":"2025-03-23T14:58:57+00:00","command_exit":{"command":["bin/respirate"],"exitstatus":1,"pid":27,"success":false}}}
Perhaps there are situations where the subprocess doesn't flush a
trailing newline.
Since `restarter` doesn't (normally) run its loop so often,
defensively print an an extra newline so that things don't look quite
as weird in those cases.
You can see the newline in the output:
$ RESTART_MINIMUM_TIME_ALIVE=10 bin/restarter bash -c 'sleep 1; echo hi; exit 1'
{"restarter":{"start_time":"2025-03-25T17:56:23+00:00","startup":{"command":["bash","-c","sleep 1; echo hi; exit 1"],"minimum_time_alive":10}}}
hi
{"restarter":{"start_time":"2025-03-25T17:56:23+00:00","command_exit":{"command":["bash","-c","sleep 1; echo hi; exit 1"],"exitstatus":1,"pid":29308,"success":false}}}
hi
{"restarter":{"start_time":"2025-03-25T17:56:23+00:00","command_exit":{"command":["bash","-c","sleep 1; echo hi; exit 1"],"exitstatus":1,"pid":29311,"success":false}}}
hi
{"restarter":{"start_time":"2025-03-25T17:56:23+00:00","command_exit":{"command":["bash","-c","sleep 1; echo hi; exit 1"],"exitstatus":1,"pid":29314,"success":false}}}
{"restarter":{"start_time":"2025-03-25T17:56:23+00:00","shutdown":{"command":["bash","-c","sleep 1; echo hi; exit 1"],"minimum_time_alive":10}}}
Which uses the same command/test methodology as
e5f9d83002
.
50 lines
1.2 KiB
Ruby
Executable File
50 lines
1.2 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
# frozen_string_literal: true
|
|
|
|
minimum_time_alive = Integer(ENV.fetch("RESTART_MINIMUM_TIME_ALIVE", "3600"), 10)
|
|
require "json"
|
|
|
|
command = ARGV.dup.freeze
|
|
start_time = Time.now
|
|
|
|
iso_start = start_time.utc.strftime("%Y-%m-%dT%H:%M:%S%:z").freeze
|
|
puts JSON.generate(restarter: {
|
|
start_time: iso_start,
|
|
startup: {
|
|
command:,
|
|
minimum_time_alive:
|
|
}
|
|
})
|
|
|
|
loop do
|
|
system(*command)
|
|
status = $?
|
|
|
|
# Extra newline to prevent blending with subprocess just in
|
|
# case. Done as a separate system call, to be extra-accommodating to
|
|
# loggers that may want process things one system call at a time:
|
|
# below PIPE_BUF each write() matches with a read().
|
|
puts
|
|
|
|
puts JSON.generate(restarter: {
|
|
start_time: iso_start,
|
|
command_exit: {
|
|
command:,
|
|
exitstatus: status.exitstatus,
|
|
pid: status.pid,
|
|
success: status.success?
|
|
}
|
|
})
|
|
|
|
sleep(rand(1..10))
|
|
|
|
if Time.now - start_time > minimum_time_alive
|
|
puts JSON.generate(restarter: {start_time: iso_start,
|
|
shutdown: {
|
|
command:,
|
|
minimum_time_alive:
|
|
}})
|
|
exit
|
|
end
|
|
end
|