Class: Phronomy::Concurrency::CancellationToken
- Inherits:
-
Object
- Object
- Phronomy::Concurrency::CancellationToken
- Defined in:
- lib/phronomy/engine/concurrency/cancellation_token.rb
Overview
Cooperative cancellation token for Agent/Tool work.
Class Method Summary collapse
-
.timeout_after(seconds) ⇒ Object
Creates a token that expires after
secondsmeasured with the monotonic clock.
Instance Method Summary collapse
-
#cancel! ⇒ self
Explicitly cancels the token and invokes each currently registered callback once.
- #cancelled? ⇒ Boolean
-
#initialize(monotonic_deadline: nil) ⇒ CancellationToken
constructor
A new instance of CancellationToken.
-
#on_cancel(&block) ⇒ self
Registers a callback for explicit cancellation.
- #raise_if_cancelled!(message = "invocation cancelled") ⇒ Object
- #remaining_monotonic_seconds ⇒ Object
Constructor Details
#initialize(monotonic_deadline: nil) ⇒ CancellationToken
Returns a new instance of CancellationToken.
16 17 18 19 20 21 |
# File 'lib/phronomy/engine/concurrency/cancellation_token.rb', line 16 def initialize(monotonic_deadline: nil) @cancelled = false @monotonic_deadline = monotonic_deadline @mutex = Mutex.new @cancel_callbacks = [] end |
Class Method Details
.timeout_after(seconds) ⇒ Object
Creates a token that expires after seconds measured with the monotonic clock.
9 10 11 12 |
# File 'lib/phronomy/engine/concurrency/cancellation_token.rb', line 9 def self.timeout_after(seconds) monotonic_deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds new(monotonic_deadline: monotonic_deadline) end |
Instance Method Details
#cancel! ⇒ self
Explicitly cancels the token and invokes each currently registered callback once. The callback registry is cleared before callbacks run so completed registrations are not retained for the lifetime of a long-lived token.
Cancellation callbacks are isolated from one another: a StandardError raised by one callback is logged and the remaining callbacks are still delivered.
66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/phronomy/engine/concurrency/cancellation_token.rb', line 66 def cancel! callbacks = @mutex.synchronize do return self if @cancelled @cancelled = true callbacks = @cancel_callbacks @cancel_callbacks = [] callbacks end callbacks.each { |callback| deliver_cancel_callback(callback) } self end |
#cancelled? ⇒ Boolean
80 81 82 83 84 85 |
# File 'lib/phronomy/engine/concurrency/cancellation_token.rb', line 80 def cancelled? return true if @mutex.synchronize { @cancelled } !@monotonic_deadline.nil? && Process.clock_gettime(Process::CLOCK_MONOTONIC) >= @monotonic_deadline end |
#on_cancel(&block) ⇒ self
Registers a callback for explicit cancellation.
Deadline expiry by itself only changes #cancelled?. Components that need
callback delivery for a monotonic deadline must promote that deadline to
cancel! through the Runtime timer queue.
Cancellation callbacks are independent notifications. Failure of one callback is logged and does not suppress delivery to other callbacks.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/phronomy/engine/concurrency/cancellation_token.rb', line 42 def on_cancel(&block) raise ArgumentError, "on_cancel requires a block" unless block already_cancelled = @mutex.synchronize do if @cancelled true else @cancel_callbacks << block false end end deliver_cancel_callback(block) if already_cancelled self end |
#raise_if_cancelled!(message = "invocation cancelled") ⇒ Object
88 89 90 |
# File 'lib/phronomy/engine/concurrency/cancellation_token.rb', line 88 def raise_if_cancelled!( = "invocation cancelled") raise Phronomy::CancellationError, if cancelled? end |
#remaining_monotonic_seconds ⇒ Object
24 25 26 27 28 29 |
# File 'lib/phronomy/engine/concurrency/cancellation_token.rb', line 24 def remaining_monotonic_seconds return nil if @monotonic_deadline.nil? remaining = @monotonic_deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC) [remaining, 0.0].max end |