Module: Polyrun::WorkerPing

Defined in:
lib/polyrun/worker_ping.rb

Overview

Writes a monotonic timestamp to POLYRUN_WORKER_PING_FILE when the test process advances (typically once per example). When location: is passed (path:line of the example), the file is two lines: timestamp, then that string. Parents use --worker-idle-timeout to detect a worker with no progress inside a single example—unlike a background thread, ping! does not run while Ruby is busy on the main thread, so a tight CPU loop or stuck native code leaves the timestamp stale.

Prefer framework installs (call from helpers after loading the runner):

require "polyrun/rspec"
Polyrun::RSpec.install_worker_ping!

require "polyrun/minitest"
Polyrun::Minitest.install_worker_ping!

Polyrun Quick runs ping! automatically when requiring the Quick stack.

Optional interval thread (+POLYRUN_WORKER_PING_THREAD=1+, POLYRUN_WORKER_PING_INTERVAL_SEC): call #ensure_interval_ping_thread! once at worker startup if you rely on periodic pings without per-example #ping!; installers call this so the env toggle works out of the box.

Class Method Summary collapse

Class Method Details

.ensure_interval_ping_thread!Object

Starts a periodic ping! thread when POLYRUN_WORKER_PING_THREAD is truthy and POLYRUN_WORKER_PING_FILE is set. Prefer per-example #ping!; safe to call more than once (idempotent). rubocop:disable ThreadSafety/ClassInstanceVariable – idempotent once-per-process latch



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
# File 'lib/polyrun/worker_ping.rb', line 42

def ensure_interval_ping_thread!
  thread_flag = ENV["POLYRUN_WORKER_PING_THREAD"]
  return unless %w[1 true yes].include?(thread_flag&.downcase)

  path = ping_file_path
  return if path.empty?

  @interval_ping_mx ||= Mutex.new
  @interval_ping_mx.synchronize do
    return if @interval_ping_started

    raw = ENV["POLYRUN_WORKER_PING_INTERVAL_SEC"].to_s.strip
    interval = Float(raw.empty? ? "15" : raw, exception: false) || 15.0
    interval = 1.0 if interval < 1.0

    ping!
    # rubocop:disable ThreadSafety/NewThread -- optional periodic ping alongside per-example ping!
    Thread.new do
      loop do
        sleep(interval)
        ping!
      rescue SystemCallError, Interrupt
        break
      end
    end
    # rubocop:enable ThreadSafety/NewThread
    @interval_ping_started = true
  end
end

.ping!(location: nil) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/polyrun/worker_ping.rb', line 23

def ping!(location: nil)
  path = ping_file_path
  return if path.empty?

  t = Process.clock_gettime(Process::CLOCK_MONOTONIC).to_s
  loc = location.to_s.strip
  payload = loc.empty? ? t : "#{t}\n#{loc}"
  File.binwrite(path, payload)
rescue SystemCallError
  # best-effort
end

.ping_file_pathObject



35
36
37
# File 'lib/polyrun/worker_ping.rb', line 35

def ping_file_path
  ENV["POLYRUN_WORKER_PING_FILE"].to_s.strip
end