Class: Zeridion::Flare::Worker::Heartbeat

Inherits:
Object
  • Object
show all
Defined in:
lib/zeridion_flare/worker/heartbeat.rb

Overview

One heartbeat pump per in-flight job, run on its own thread.

Cadence (frozen protocol §3): every max(10s, timeout_seconds / 3), integer floor-div on the SECONDS, with the 10 s floor shrinkable for tests via Configuration#heartbeat_min_ms (FLARE_HEARTBEAT_MIN_MS seam).

A heartbeat is emitted IMMEDIATELY on claim (the first beat is not delayed) so a long job lands in the server reaper's forgiving "heartbeated

  • silent for GREATEST(120s, timeout × ⅔)" window rather than the strict "never-heartbeated + StartedAt + timeout" branch.

The pump keeps beating until the HANDLER finishes (the stop signal is raised only when #perform returns or raises). On a server "cancel" response it trips the cancellation token (cooperative cancel) but KEEPS beating while the handler winds down, so a cancelled-but-not-yet-returned job isn't reaped mid-unwind. Heartbeats are best-effort: a failed beat is swallowed (the job keeps running); only a "cancel" status or host shutdown stops execution.

Instance Method Summary collapse

Constructor Details

#initialize(client:, worker_id:, job_id:, timeout_seconds:, progress_slot:, cancellation:, stop:, heartbeat_min_ms:, logger: nil) ⇒ Heartbeat

Returns a new instance of Heartbeat.

Parameters:

  • client (Object)

    worker HTTP client exposing #heartbeat(body) (strict)

  • worker_id (String)
  • job_id (String)
  • timeout_seconds (Integer)

    the job item's timeout (cadence base)

  • progress_slot (ProgressSlot)
  • cancellation (CancellationToken)

    tripped on a "cancel" response

  • stop (CancellationToken)

    internal latch; cancel!'d when the handler finishes so the pump exits

  • heartbeat_min_ms (Integer)

    floor on the cadence (ms)

  • logger (Logger, nil) (defaults to: nil)


35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/zeridion_flare/worker/heartbeat.rb', line 35

def initialize(client:, worker_id:, job_id:, timeout_seconds:, progress_slot:,
               cancellation:, stop:, heartbeat_min_ms:, logger: nil)
  @client = client
  @worker_id = worker_id
  @job_id = job_id
  @timeout_seconds = timeout_seconds
  @progress_slot = progress_slot
  @cancellation = cancellation
  @stop = stop
  @heartbeat_min_ms = heartbeat_min_ms
  @logger = logger
  @thread = nil
end

Instance Method Details

#interval_secondsObject

The cadence in seconds: max(floor, timeout/3) where floor honors the heartbeat_min_ms seam. Pure / side-effect-free so tests can assert it without spinning a thread.



52
53
54
55
56
# File 'lib/zeridion_flare/worker/heartbeat.rb', line 52

def interval_seconds
  floor = @heartbeat_min_ms / 1000.0
  third = @timeout_seconds.to_i / 3 # integer floor-div on seconds, per spec
  [floor, third].max
end

#startObject

Start the pump thread. Emits the immediate beat, then loops on the cadence until stop is signalled.



60
61
62
63
64
65
66
# File 'lib/zeridion_flare/worker/heartbeat.rb', line 60

def start
  @thread = Thread.new do
    Thread.current.name = "flare-heartbeat-#{@job_id}" if Thread.current.respond_to?(:name=)
    run
  end
  self
end

#stop_and_join(timeout: nil) ⇒ Object

Signal the pump to stop (handler finished) and join its thread.



69
70
71
72
73
# File 'lib/zeridion_flare/worker/heartbeat.rb', line 69

def stop_and_join(timeout: nil)
  @stop.cancel!
  @thread&.join(timeout)
  nil
end