Class: Plushie::TimerScheduler
- Inherits:
-
Object
- Object
- Plushie::TimerScheduler
- Defined in:
- lib/plushie/timer_scheduler.rb,
sig/plushie/timer_scheduler.rbs
Overview
Single-thread timer scheduler for timer subscriptions.
Replaces the per-timer Thread.new pattern with one thread that manages all timers via IO.select with a deadline-based timeout. Adding or cancelling a timer wakes the scheduler through a pipe so it can recalculate the next deadline immediately.
Instance Method Summary collapse
- #cancel(tag)
- #drain_pipe
-
#initialize ⇒ TimerScheduler
constructor
A new instance of TimerScheduler.
- #run_loop
- #schedule(tag:, interval_ms:, event_queue:)
- #stop
- #wake
Constructor Details
#initialize ⇒ TimerScheduler
Returns a new instance of TimerScheduler.
19 20 21 22 23 24 25 26 |
# File 'lib/plushie/timer_scheduler.rb', line 19 def initialize @pipe_r, @pipe_w = IO.pipe @timers = {} @mutex = Mutex.new @stop_mutex = Mutex.new @thread = Thread.new { run_loop } @thread.name = "plushie-timer-scheduler" end |
Instance Method Details
#cancel(tag)
This method returns an undefined value.
40 41 42 43 |
# File 'lib/plushie/timer_scheduler.rb', line 40 def cancel(tag) @mutex.synchronize { @timers.delete(tag) } wake end |
#drain_pipe
This method returns an undefined value.
68 69 70 71 72 |
# File 'lib/plushie/timer_scheduler.rb', line 68 def drain_pipe @pipe_r.read_nonblock(4096) rescue IOError, IO::EAGAINWaitReadable nil end |
#run_loop
This method returns an undefined value.
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 |
# File 'lib/plushie/timer_scheduler.rb', line 74 def run_loop loop do now = Process.clock_gettime(Process::CLOCK_MONOTONIC) next_deadline = nil timers_to_fire = [] @mutex.synchronize do @timers.each do |tag, timer| if now >= timer[:deadline] timers_to_fire << [tag, timer[:queue]] timer[:deadline] = now + timer[:interval] end next_deadline = timer[:deadline] if next_deadline.nil? || timer[:deadline] < next_deadline end end timers_to_fire.each do |tag, queue| BoundedQueue.push(queue, [:timer_tick, tag]) end drain_pipe timeout = next_deadline ? [next_deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC), 0.001].max : 3600 IO.select([@pipe_r], [], [], timeout) end rescue IOError # Pipe closed during shutdown end |
#schedule(tag:, interval_ms:, event_queue:)
This method returns an undefined value.
28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/plushie/timer_scheduler.rb', line 28 def schedule(tag:, interval_ms:, event_queue:) interval = interval_ms / 1000.0 @mutex.synchronize do @timers[tag] = { interval: interval, deadline: Process.clock_gettime(Process::CLOCK_MONOTONIC) + interval, queue: event_queue } end wake end |
#stop
This method returns an undefined value.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/plushie/timer_scheduler.rb', line 45 def stop thread = nil @stop_mutex.synchronize do thread = @thread @thread = nil @pipe_w&.close unless @pipe_w&.closed? @pipe_r&.close unless @pipe_r&.closed? end return unless thread return if thread == Thread.current thread.kill thread.join(0.5) end |
#wake
This method returns an undefined value.
62 63 64 65 66 |
# File 'lib/plushie/timer_scheduler.rb', line 62 def wake @pipe_w.write_nonblock(".") rescue IOError, Errno::EPIPE nil end |