Class: Harnex::RunWatcher
- Inherits:
-
Object
- Object
- Harnex::RunWatcher
- Defined in:
- lib/harnex/commands/watch.rb
Constant Summary collapse
- DEFAULT_STALL_AFTER_S =
8 * 60.0
- DEFAULT_MAX_RESUMES =
1- POLL_INTERVAL_S =
60.0- MAX_STATUS_ERRORS =
3- RESUME_TEXT =
"resume"
Instance Method Summary collapse
-
#initialize(id:, repo_root:, stall_after_s: DEFAULT_STALL_AFTER_S, max_resumes: DEFAULT_MAX_RESUMES, poll_interval_s: POLL_INTERVAL_S, sleeper: nil, monotonic_clock: nil, out: $stdout, err: $stderr) ⇒ RunWatcher
constructor
A new instance of RunWatcher.
- #run ⇒ Object
Constructor Details
#initialize(id:, repo_root:, stall_after_s: DEFAULT_STALL_AFTER_S, max_resumes: DEFAULT_MAX_RESUMES, poll_interval_s: POLL_INTERVAL_S, sleeper: nil, monotonic_clock: nil, out: $stdout, err: $stderr) ⇒ RunWatcher
Returns a new instance of RunWatcher.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/harnex/commands/watch.rb', line 13 def initialize( id:, repo_root:, stall_after_s: DEFAULT_STALL_AFTER_S, max_resumes: DEFAULT_MAX_RESUMES, poll_interval_s: POLL_INTERVAL_S, sleeper: nil, monotonic_clock: nil, out: $stdout, err: $stderr ) @id = Harnex.normalize_id(id) @repo_root = repo_root @stall_after_s = Float(stall_after_s) @max_resumes = Integer(max_resumes) @poll_interval_s = Float(poll_interval_s) @sleeper = sleeper || ->(seconds) { sleep(seconds) } @monotonic_clock = monotonic_clock || -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) } @out = out @err = err end |
Instance Method Details
#run ⇒ Object
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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/harnex/commands/watch.rb', line 35 def run polls = 0 resumes = 0 final_state = "unknown" outcome = :error status_errors = 0 start_at = now @out.puts( "harnex watch: id=#{@id} stall-after=#{format_duration(@stall_after_s)} " \ "max-resumes=#{@max_resumes} poll=#{format_duration(@poll_interval_s)}" ) loop do polls += 1 snapshot = fetch_snapshot case snapshot[:kind] when :exited final_state = "exited" outcome = :exited @out.puts("harnex watch: session exited") break when :error if snapshot[:fatal] @err.puts("harnex watch: #{snapshot[:error]}") outcome = :error break end status_errors += 1 if status_errors >= MAX_STATUS_ERRORS @err.puts("harnex watch: #{snapshot[:error]} (status retry limit reached)") outcome = :error break end when :status status_errors = 0 final_state = snapshot[:agent_state] if snapshot[:stalled] if resumes < @max_resumes send_resume(snapshot[:registry]) resumes += 1 @out.puts( "harnex watch: resume #{resumes}/#{@max_resumes} " \ "(idle=#{format_duration(snapshot[:idle_seconds])}, state=#{final_state})" ) else outcome = :escalated @out.puts("harnex watch: max resumes reached, escalating") break end end end @sleeper.call(@poll_interval_s) end elapsed = (now - start_at).round(1) @out.puts( "harnex watch: summary id=#{@id} polls=#{polls} resumes=#{resumes} " \ "final_state=#{final_state} outcome=#{outcome} elapsed_s=#{elapsed}" ) outcome_to_exit_code(outcome) rescue StandardError => e @err.puts("harnex watch: #{e.}") 1 end |