pub struct TimerService { /* private fields */ }Expand description
Durable timer scheduling and wheel-fire handling.
The service owns the AT live path for timers. Workflow-issued TimerStarted events are recorded
by AD’s resume-live handoff before this service is called; this service persists only the durable
timer row and later asynchronous arrival/cancellation history through the engine recorder seam.
Implementations§
Source§impl TimerService
impl TimerService
Sourcepub fn new(
engine: Arc<dyn EngineHandle>,
store: Arc<dyn ReadableEventStore>,
) -> Self
pub fn new( engine: Arc<dyn EngineHandle>, store: Arc<dyn ReadableEventStore>, ) -> Self
Creates a durable timer service from the engine seam and timer store.
Sourcepub fn with_recorded_at(
engine: Arc<dyn EngineHandle>,
store: Arc<dyn ReadableEventStore>,
recorded_at: fn() -> DateTime<Utc>,
) -> Self
pub fn with_recorded_at( engine: Arc<dyn EngineHandle>, store: Arc<dyn ReadableEventStore>, recorded_at: fn() -> DateTime<Utc>, ) -> Self
Creates a durable timer service with an injected history timestamp source.
Sourcepub fn with_terminal_updates(
self,
terminal_updates: Arc<DashSet<(WorkflowId, TimerId)>>,
) -> Self
pub fn with_terminal_updates( self, terminal_updates: Arc<DashSet<(WorkflowId, TimerId)>>, ) -> Self
Replaces this service’s per-timer terminal-update coordinator with a shared one, returning the service for chaining.
The production timer bridge owns ONE coordinator and hands it to every
TimerService it constructs, so a cancel obtained from one service and
a fire obtained from another still serialize per timer (first-recorded
wins). Without this, each service would guard against itself only.
Sourcepub fn with_deadline_handler(self, handler: Arc<dyn DeadlineHandler>) -> Self
pub fn with_deadline_handler(self, handler: Arc<dyn DeadlineHandler>) -> Self
Registers the engine-side deadline handler for reserved deadline:{run_id}
fires, returning the service for chaining.
The production timer bridge calls this so both the live wheel and
the boot/adoption sweep (which share Self::fire_timer) demux a deadline fire to
the handler instead of recording a generic TimerFired.
Sourcepub async fn schedule(
&self,
workflow_id: WorkflowId,
timer_id: TimerId,
fire_at: DateTime<Utc>,
armed_seq: u64,
) -> Result<(), TimerServiceError>
pub async fn schedule( &self, workflow_id: WorkflowId, timer_id: TimerId, fire_at: DateTime<Utc>, armed_seq: u64, ) -> Result<(), TimerServiceError>
Schedules a durable timer and arms the live wheel when the workflow is resident.
The operation persists the durable timer row and arms the wheel when needed. The
command-issued TimerStarted recorder event is appended by AD’s resume-live handoff before
AE/AT reaches this service, so this method deliberately does not record it again;
armed_seq is that recorded event’s workflow-history sequence and becomes the row’s
identity component (aion_store::TimerEntry::armed_seq), so retirement can tell this
arming from a re-arm to the identical instant.
§Errors
Returns TimerServiceError when durable storage, recording, residency resolution, or wheel
arming fails.
Sourcepub async fn cancel(
&self,
workflow_id: WorkflowId,
timer_id: TimerId,
cause: TimerCancelCause,
) -> Result<(), TimerServiceError>
pub async fn cancel( &self, workflow_id: WorkflowId, timer_id: TimerId, cause: TimerCancelCause, ) -> Result<(), TimerServiceError>
Cancels a durable timer that has not already reached a terminal timer state.
Already-fired and already-cancelled timers are treated as idempotent no-ops. For active
resident timers the live wheel is disarmed through the engine seam before TimerCancelled is
recorded through the workflow recorder seam. Non-resident timers still record the cancellation
so recovery/replay can suppress a later fire.
Anonymous timers are accepted: authors can never address one (the SDK’s cancel_timer
takes a TimerRef minted by start_timer, which is always named), but the engine settles
with_timeout scope deadlines — anonymous by construction — through this first-recorded-wins
race against Self::fire_timer.
§Errors
Returns TimerServiceError when history inspection, residency resolution, wheel disarming,
or event recording fails.
Sourcepub async fn fire_timer(
&self,
workflow_id: WorkflowId,
timer_id: TimerId,
fire_at: DateTime<Utc>,
) -> Result<(), TimerServiceError>
pub async fn fire_timer( &self, workflow_id: WorkflowId, timer_id: TimerId, fire_at: DateTime<Utc>, ) -> Result<(), TimerServiceError>
Handles a live timer-wheel fire.
TimerFired is recorded before any mailbox delivery. If the workflow is no longer resident,
the recorded event remains the durable observation that replay/recovery can surface later.
A fire whose TimerFired is ALREADY the timer’s last recorded event (an earlier append
landed while its acknowledgement was lost — aion#145) is not a no-op: for a resident
workflow the fire re-enters the recorder seam, which reconciles the recorder’s sequence
forward without appending, and the owed mailbox wake is delivered.
§Errors
Returns TimerServiceError when history inspection, recording, residency resolution, or
live mailbox delivery fails.