queue() as soon as possible, schedule() once after a delay, every() on a fixed
interval. Reach for a task whenever work doesn’t have to finish inside the inbound
call: an inbound method has a 30-second budget, while a task runs in the alarm turn
with a budget on the order of minutes — so the pattern for LLM and outbound API work
is record intent, queue() the work, return immediately.
How Agents Run walks through that loop;
budgets live in Limits.
queue()
Schedule a persistent task to run as soon as possible — identical toprotectedqueue(method,payload?,opts?):Promise<string>
schedule(0, method, payload, opts).
The canonical “think in the background” move: append to history in the
inbound method, queue() the slow work, return immediately. Same
dispatch, retry, and idempotency semantics as
`schedule`.
Parameters
Returns
Promise<string>
The task id.
schedule()
Schedule a persistent task to run once,protectedschedule(delaySeconds,method,payload?,opts?):Promise<string>
delaySeconds from now.
A task names a method on your class: when the timer fires, the SDK calls
this[method](payload) — one argument, the payload. If no such method
exists, `onTask` fires instead. Tasks are persistent:
they survive crashes and restarts, riding the actor’s single alarm slot.
Delivery is at-least-once — write handlers to be idempotent. A task that
throws is retried with exponential backoff (starting around a second,
capped at 5 minutes) up to opts.maxRetries times after the first
delivery (default 5), then parked (dropped without firing again).
With a stable opts.id, scheduling is an upsert — the prior task with
that id is replaced and the timer re-armed. Payloads must be
storage-codec-safe or a CodecError is thrown.
Parameters
Returns
Promise<string>
The task id (pass to
`cancelSchedule`).
every()
Schedule a persistent task to run repeatedly at a fixed interval. The first fire isprotectedevery(intervalSeconds,method,payload?,opts?):Promise<string>
intervalSeconds from now. After each successful run
the next fire is scheduled one interval from the start of the drain turn,
and the attempt counter resets. Failed runs retry with backoff like any
other task. Use a stable opts.id to make re-arming an upsert (e.g. on
every activation).
Parameters
Returns
Promise<string>
The task id.
ScheduleOptions
Options for schedule()/queue()/every(). Properties everyMs?Recurrence interval in ms. Set by every(); re-inserts the next fire.optionaleveryMs?:number
id?
Stable id. Re-scheduling with the same id replaces the prior task (dedup + re-arm). Omit for a random id. Must not contain a codec-unsafe value; keep it a plain string.optionalid?:string
maxRetries?
Retries AFTER the first delivery before the task is parked (dropped). Default 5, so a task runs up tooptionalmaxRetries?:number
maxRetries + 1 times total.
Dispatch
- A due task calls
this[task.name](task.payload)— one argument, the payload. - If no such method exists, the fallback fires instead:
onTask(name, payload, { attempt }). - Task methods are ordinary methods. A method that should be schedulable but not
RPC-callable from a stub can be named with a leading
_— the runtime excludes_-names from RPC, but the scheduler still dispatches to them.
onTask()
Hook: fallback for a due task whoseprotectedonTask(_name,_payload,_ctx):Promise<void>
name is not a method on the
subclass. The common path dispatches straight to the named method; this
fires only when that lookup misses. The default implementation does
nothing (the task is treated as delivered).
Parameters
Returns
Promise<void>
now()
Time source for the scheduler. Override in tests for a deterministic clock; every scheduling decision (protectednow():number
queue / schedule / every / task draining) reads time through it.
Returns
number
The current time in epoch milliseconds.
Default Value
Date.now()
Failure and retries
- A task that throws is retried with exponential backoff (starting around a second,
capped at 5 minutes), up to
maxRetriestimes after the first delivery — 6 runs total by default. - A task that exhausts its retries is parked: deleted without firing again, and there is no callback when that happens.
- A recurring (
every) task resets its attempt count after each successful run, and schedules its next fire from the start of the drain turn (the timestamp captured before dispatch), not from when the method returns.
Delivery contract
Delivery is at-least-once: a crash after your method runs but before the task is marked done re-runs it on the next activation. Write task handlers to be idempotent — the same rule as alarm handlers. Payloads are stored in the actor’s persistent storage and must be codec-safe — JSON-native values plusDate, Map, Set, ArrayBuffer/TypedArray, BigInt, RegExp.
Functions, class instances, or circular references throw a CodecError — see
Errors.
cancelSchedule()
Cancel a pending task by id. Removes the task and re-arms the alarm to the next remaining deadline. ParametersprotectedcancelSchedule(id):Promise<boolean>
Returns
Promise<boolean>
true if a pending task was removed; false if no task with
that id exists.
listSchedules()
List every pending task on this agent. ReturnsprotectedlistSchedules():Promise<TaskRecord[]>
Promise<TaskRecord[]>
One TaskRecord per pending task — id, method name,
payload, next due time, recurrence, and retry counters.
TaskRecord
A persistent scheduled task, as returned bylistSchedules().
Properties
attempts
attempts: number
Consecutive failed deliveries so far; resets after a successful recurring run.
createdAt
createdAt: Date
When the task was first scheduled.
due
due: number
Epoch ms at which the task becomes due.
everyMs?
Recurrence interval in ms, if this is a repeating task.optionaleveryMs?:number
id
id: string
The task id — random unless a stable id was supplied at scheduling time.
maxRetries
maxRetries: number
Retries allowed after the first delivery before the task is parked.
name
name: string
The method name the task will call when it fires (or the name handed to
the onTask fallback if no such method exists).
payload?
Arbitrary payload. MUST be codec-safe (JSON-native + Date/Map/Set/ ArrayBuffer/TypedArray/Buffer/BigInt/RegExp) — it is stored viaoptionalpayload?:unknown
ctx.storage.put, which throws CodecError on functions, class instances,
or circular refs.