Class: Phronomy::Concurrency::CancellationToken
- Inherits:
-
Object
- Object
- Phronomy::Concurrency::CancellationToken
- Defined in:
- lib/phronomy/concurrency/cancellation_token.rb
Overview
Provides cooperative cancellation for agent invocations.
Pass a token to an agent via +config: { cancellation_token: token }+. The agent checks the token before each LLM call and raises Phronomy::CancellationError when the token is cancelled or the optional deadline has passed.
A token may be shared across multiple agent invocations and across threads; all access to internal state is protected by a Mutex.
Instance Attribute Summary collapse
-
#deadline ⇒ Time?
readonly
The wall-clock deadline passed to #initialize, or +nil+.
Class Method Summary collapse
-
.timeout_after(seconds) ⇒ CancellationToken
Returns a new token that will expire after +seconds+ seconds, measured with the monotonic clock (+Process::CLOCK_MONOTONIC+).
Instance Method Summary collapse
-
#cancel! ⇒ self
Mark the token as cancelled and fire any registered #on_cancel callbacks.
-
#cancelled? ⇒ Boolean
Returns +true+ when the token has been explicitly cancelled via #cancel!, when the wall-clock deadline has passed, or when the monotonic deadline (set by CancellationToken.timeout_after) has elapsed.
-
#initialize(deadline: nil, monotonic_deadline: nil) ⇒ CancellationToken
constructor
mutant:disable - removing @cancelled = false is equivalent because nil is falsey.
-
#on_cancel { ... } ⇒ self
Registers a one-shot callback invoked when this token is explicitly cancelled via #cancel!.
-
#raise_if_cancelled!(message = "invocation cancelled") ⇒ nil
Raises Phronomy::CancellationError if the token is cancelled.
-
#remaining_monotonic_seconds ⇒ Float?
Returns the remaining seconds until the monotonic deadline fires, or +nil+ when no monotonic deadline is set.
Constructor Details
#initialize(deadline: nil, monotonic_deadline: nil) ⇒ CancellationToken
mutant:disable - removing @cancelled = false is equivalent because nil is falsey
52 53 54 55 56 57 58 |
# File 'lib/phronomy/concurrency/cancellation_token.rb', line 52 def initialize(deadline: nil, monotonic_deadline: nil) @cancelled = false @deadline = deadline @monotonic_deadline = monotonic_deadline @mutex = Mutex.new @cancel_callbacks = [] end |
Instance Attribute Details
#deadline ⇒ Time? (readonly)
Returns the wall-clock deadline passed to #initialize, or +nil+.
61 62 63 |
# File 'lib/phronomy/concurrency/cancellation_token.rb', line 61 def deadline @deadline end |
Class Method Details
.timeout_after(seconds) ⇒ CancellationToken
Returns a new token that will expire after +seconds+ seconds, measured with the monotonic clock (+Process::CLOCK_MONOTONIC+). Unlike constructing a token with +deadline: Time.now + seconds+, this factory is immune to NTP adjustments and DST transitions.
40 41 42 43 |
# File 'lib/phronomy/concurrency/cancellation_token.rb', line 40 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
Mark the token as cancelled and fire any registered #on_cancel callbacks. Thread-safe; idempotent — calling multiple times has no additional effect. mutant:disable - mutex removal and dup-vs-ref mutations are GVL-safe equivalents
103 104 105 106 107 108 109 110 111 |
# File 'lib/phronomy/concurrency/cancellation_token.rb', line 103 def cancel! callbacks = @mutex.synchronize do return self if @cancelled @cancelled = true @cancel_callbacks.dup end callbacks.each(&:call) self end |
#cancelled? ⇒ Boolean
Returns +true+ when the token has been explicitly cancelled via #cancel!, when the wall-clock deadline has passed, or when the monotonic deadline (set by timeout_after) has elapsed. Thread-safe. mutant:disable - mutex removal on @cancelled read is GVL-safe equivalent under MRI
119 120 121 122 123 124 |
# File 'lib/phronomy/concurrency/cancellation_token.rb', line 119 def cancelled? return true if @mutex.synchronize { @cancelled } return true if !@deadline.nil? && Time.now >= @deadline !@monotonic_deadline.nil? && Process.clock_gettime(Process::CLOCK_MONOTONIC) >= @monotonic_deadline end |
#on_cancel { ... } ⇒ self
Registers a one-shot callback invoked when this token is explicitly cancelled via #cancel!. If the token is already cancelled, the block is called immediately (still within the caller's thread).
Callbacks are NOT fired for deadline-based cancellation (i.e. when #cancelled? returns +true+ due to +@monotonic_deadline+ expiry). Use Runtime#timer_queue to schedule deadline callbacks.
mutant:disable - mutex removal mutation is GVL-safe equivalent under MRI
85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/phronomy/concurrency/cancellation_token.rb', line 85 def on_cancel(&block) already_cancelled = @mutex.synchronize do if @cancelled true else @cancel_callbacks << block false end end block.call if already_cancelled self end |
#raise_if_cancelled!(message = "invocation cancelled") ⇒ nil
Raises Phronomy::CancellationError if the token is cancelled. A convenience method for cooperative cancellation checks inside tools, RAG loaders, and hooks, replacing the +if cancelled? then raise+ pattern.
mutant:disable - raise(CancellationError) resolves to raise(Phronomy::CancellationError) in this namespace
135 136 137 |
# File 'lib/phronomy/concurrency/cancellation_token.rb', line 135 def raise_if_cancelled!( = "invocation cancelled") raise Phronomy::CancellationError, if cancelled? end |
#remaining_monotonic_seconds ⇒ Float?
Returns the remaining seconds until the monotonic deadline fires, or +nil+ when no monotonic deadline is set. Returns 0.0 if already past.
67 68 69 70 71 |
# File 'lib/phronomy/concurrency/cancellation_token.rb', line 67 def remaining_monotonic_seconds return nil if @monotonic_deadline.nil? remaining = @monotonic_deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC) [remaining, 0.0].max end |