This page lists every export of agents/lifecycle. For a guided introduction, refer to Lifecycle and Build a capability.
agents/lifecycle is stable.
| Export | Kind | Description |
|---|---|---|
Lifecycle |
Class | Installs on a Durable Object and runs startup, routing, jobs, and the alarm |
LifecycleOptions |
Type | Options for Lifecycle.install() and new Lifecycle() |
LifecycleObject |
Interface | A Durable Object with a lifecycle field and host hooks |
LifecycleCapability |
Abstract class | Base class for capabilities that use Lifecycle services |
DurableObjectCapability |
Interface | The hooks the Lifecycle calls on a capability |
LifecycleServices |
Type | Services available to a LifecycleCapability as this.lifecycle |
LifecycleStatus |
Type | "zero", "starting", or "started" |
LifecycleSockets |
Type | Hibernatable WebSocket access for a capability |
LifecycleEvents |
Type | Best-effort event publishing for a capability |
LifecycleEvent |
Type | One published event |
LifecycleRoutes |
Type | Message routing between Lifecycles |
LifecycleRouteAddress |
Type | Address of a routed Lifecycle |
LifecycleRouteContext |
Type | Argument of onRoute() |
LifecycleHostContextScope |
Type | Connection and request passed to runInHostContext() |
CapabilityStartContext |
Type | Argument of a capability's onStart() |
CapabilityRequestContext |
Type | Argument of onRequest() |
CapabilityWebSocketUpgradeContext |
Type | Argument of onWebSocketUpgrade() |
LifecycleJobs |
Type | Job queue access for the host or one capability |
LifecycleJob |
Type | One stored job |
LifecycleJobPushOptions |
Type | Options for jobs.push() |
LifecycleJobContext |
Type | Argument of onJob() and onJobError() |
LifecycleJobOutcome |
Type | Return value of onJob() and onJobError() |
MemoryLimitContext |
Type | Argument of onMemoryLimit() and onAlarmMemoryLimit() |
getCurrentAgent |
Function | Reads the current object, request, and connection |
CurrentAgentContext |
Type | Return value of getCurrentAgent() |
Connection |
Type | A WebSocket connection managed by a capability |
ConnectionContext |
Type | Context passed when a connection is accepted |
ConnectionState |
Type | Read-only state stored on a connection |
ConnectionSetStateFn |
Type | Updater function for connection.setState() |
WSMessage |
Type | A WebSocket message: string, ArrayBuffer, or ArrayBufferView |
Lifecycle<Env, Props> is generic over the Worker environment and the type of startup props.
| Member | Description |
|---|---|
Lifecycle.install(host, options?) |
Constructs a Lifecycle and calls installHandlers(). Returns the Lifecycle. |
new Lifecycle(host, options?) |
Constructs a Lifecycle without installing handlers. |
installHandlers() |
Installs fetch, alarm, webSocketMessage, webSocketClose, and webSocketError on the host, unless the host already defines them. Throws if called twice. |
| Member | Returns | Description |
|---|---|---|
use(capability) |
this |
Installs a capability. Throws after startup, on a duplicate ID, or on a second catch-all for the same hook. |
start(props?) |
Promise<void> |
Starts capabilities and the host. Called for you on fetch, alarm, and WebSocket events. Call it in RPC methods. |
isStarted() |
boolean |
true after every capability and the host onStart() have finished. |
name |
string |
The object's name from ctx.id.name. Throws when the object has no name. |
jobs |
LifecycleJobs |
The host's view of the job queue. |
sql`...` |
T[] |
Runs a query against the object's SQLite database with bound parameters. |
rearmAlarm() |
Promise<void> |
Sets the alarm from the job queue. Queue changes call this for you. |
trackAlarmWork(promise) |
boolean |
Keeps work handed off by a job inside the current alarm's memory-limit protection. Returns false outside an alarm. |
dispose() |
Promise<void> |
Calls each capability's dispose() in reverse registration order. |
disableAlarms() |
Promise<void> |
Deletes the alarm and stops the Lifecycle from setting it again. Use during teardown. |
| Option | Type | Default | Description |
|---|---|---|---|
maxAlarmMemoryLimitStrikes |
number |
3 |
Consecutive memory-limit resets before the breaker deletes recovery jobs. For more information, refer to Memory-limit protection. |
LifecycleObject<Env, Props> extends DurableObject<Env> with a lifecycle: Lifecycle<Env, Props> field and these optional host hooks. Each one runs inside the host context:
| Hook | Returns | When it runs |
|---|---|---|
onStart(props?) |
void | Promise<void> |
Once per in-memory lifetime, after every capability has started |
onRequest(request) |
Response | Promise<Response> |
For each HTTP request no capability handled |
onAlarm() |
void | Promise<void> |
Once per alarm, after due jobs |
onJob(context) |
LifecycleJobOutcome | void or a promise |
When a host job comes due |
onAlarmMemoryLimit(context) |
void | Promise<void> |
After an alarm ends in a memory-limit reset, after capability hooks |
LifecycleObject is the default type parameter of getCurrentAgent().
DurableObjectCapability<Props> is the interface the Lifecycle calls. Every hook is optional. Hooks run outside the host context.
| Member | Returns | Description |
|---|---|---|
claims |
"selective" | "catch-all" |
How the capability claims traffic. Defaults to "selective". For more information, refer to Capability order. |
onStart(context) |
void |
Creates tables or restores state. Runs in registration order, before the host onStart(). context.props holds the startup props. |
onRequest(context) |
Response | undefined |
Handles an HTTP request by returning a Response, or passes it on with undefined. |
onWebSocketUpgrade(context) |
Response | undefined |
Claims a WebSocket upgrade by returning a Response. The capability then owns the socket for its whole lifetime. |
onWebSocketMessage(ws, message) |
boolean | void |
Handles a message on a hibernated socket. Return true to consume it. |
onWebSocketClose(ws, code, reason, wasClean) |
boolean | void |
Handles a close on a hibernated socket. Return true to consume it. |
onWebSocketError(ws, error) |
boolean | void |
Handles an error on a hibernated socket. Return true to consume it. |
onJob(context) |
LifecycleJobOutcome | void |
Runs one due job the capability pushed. Keep it short. |
onJobError(context, error) |
LifecycleJobOutcome | void |
Runs after a job fails its last retry. The return value decides what happens to the job. Returning nothing completes it. |
onMemoryLimit(context) |
void |
Applies policy after an alarm ends in a memory-limit reset. Runs before the host's onAlarmMemoryLimit(). Keep writes small. |
onRoute(context) |
unknown |
Handles a message routed to this capability's ID. The return value goes back to the sender. |
dispose() |
void |
Releases live resources during explicit teardown. Does not run on eviction. |
Any hook can also return a promise of its result.
The Lifecycle dispatches each hook as follows:
onStart()runs on every capability, in registration order.onRequest()andonWebSocketUpgrade()are offered in registration order, with the catch-all last. The firstResponsewins.onWebSocketMessage(),onWebSocketClose(), andonWebSocketError()are offered in registration order until one returnstrue. Events that no capability consumes are ignored.onJob()andonJobError()go only to the capability that pushed the job.onRoute()goes only to the capability whose ID the message names.onMemoryLimit()runs on every capability. A failure in one does not stop the next.dispose()runs on every capability, in reverse registration order. A failure in one does not stop the next.
| Type | Fields |
|---|---|
CapabilityStartContext<Props> |
props: Props | undefined |
CapabilityRequestContext |
request: Request |
CapabilityWebSocketUpgradeContext |
request: Request |
LifecycleJobContext |
job: LifecycleJob, attempt: number |
LifecycleRouteContext |
source: LifecycleRouteAddress | undefined, payload: unknown |
MemoryLimitContext |
sealed, nextTime?, executing?, purgedRecoveryLoopJobs?. For more information, refer to Memory-limit protection. |
LifecycleCapability<Props> is an abstract class that implements DurableObjectCapability. Extend it to receive Lifecycle services.
| Member | Description |
|---|---|
constructor(id) |
Protected. Takes the capability's stable ID. Throws on an empty ID. |
capabilityId |
The ID passed to the constructor. Jobs, events, and routed messages use it. |
claims |
"selective" by default. Override it with "catch-all" when the capability handles all traffic for its hooks. |
onStart(context) |
Does nothing by default. Override it to create tables or restore state. |
lifecycle |
Protected. The capability's LifecycleServices. Throws if the capability is not installed. |
lifecycleServices |
Protected. The same services, or undefined before installation. |
A LifecycleCapability reads these services from this.lifecycle:
| Member | Type | Description |
|---|---|---|
name |
string |
The object's name. Same as Lifecycle.name. |
className |
string |
The host class name, as exported from the Worker. |
storage |
DurableObjectStorage |
The object's storage, including storage.sql. |
sockets |
LifecycleSockets |
Accepts and lists hibernatable WebSockets. |
ready() |
() => Promise<void> |
Resolves once startup has finished, starting the object if needed. Rejects if startup fails. Resolves immediately inside startup. |
status() |
() => LifecycleStatus |
"zero" before startup, "starting" during startup, and "started" after. |
jobs |
LifecycleJobs |
The capability's own view of the job queue. |
trackAlarmWork(promise) |
(work: Promise<unknown>) => boolean |
Keeps work handed off by onJob() inside the current alarm's memory-limit protection. Returns false outside an alarm. |
runInHostContext(fn, scope?) |
Promise<unknown> |
Runs user code inside the host context, so getCurrentAgent() works. scope is a LifecycleHostContextScope. |
events |
LifecycleEvents |
Publishes best-effort events. |
routes |
LifecycleRoutes |
Sends messages to a capability with the same ID on another Lifecycle. |
| Member | Description |
|---|---|
accept(ws, tags) |
Accepts a server-side WebSocket for hibernation with the given tags. |
get(tag?) |
Returns every hibernated WebSocket on the object, optionally filtered by tag. |
These are the Durable Object's ctx.acceptWebSocket() and ctx.getWebSockets(). get() returns sockets that other capabilities own too, so filter by your own tag.
| Field | Type | Description |
|---|---|---|
connection |
Connection | undefined |
The connection the user code runs on behalf of |
request |
Request | undefined |
The request the user code runs on behalf of |
events.emit(type, payload) publishes a LifecycleEvent with these fields:
| Field | Type | Description |
|---|---|---|
source |
string |
The capability ID, or "lifecycle" for queue events |
type |
string |
Event name, such as uptime:check |
payload |
unknown |
Event data |
Both source and type must be non-empty. Events emitted before startup finishes are held until it does. On a plain Durable Object, the Lifecycle publishes each event to an agents:* diagnostics channel chosen by the prefix of type. Unknown prefixes go to agents:lifecycle. The published message adds the host class name as agent, the object name, and a timestamp.
| Member | Description |
|---|---|
source |
This Lifecycle's LifecycleRouteAddress, or undefined on a root object. |
toRoot(payload) |
Sends payload to the capability with the same ID on the root Lifecycle, and resolves to its onRoute() result. |
to(target, payload) |
Sends payload to the capability with the same ID on the Lifecycle at target. |
A LifecycleRouteAddress has a key, used for equality and storage, and a serialized data string.
Routing between Lifecycles needs a transport that the host provides. The Agent class provides one for its sub-agents. On a plain Durable Object there is no transport: source is undefined, toRoot() delivers to the capability's own onRoute() on the same object, and to() throws.
A capability that accepts its own WebSockets claims the upgrade, accepts the socket through sockets.accept(), and marks it with a hibernation attachment. After a wake, the Lifecycle offers each socket event to every capability in order, so each capability must recognize its own sockets and return true only for those:
import { LifecycleCapability } from "agents/lifecycle";
const TAG = "echo";
export class EchoSockets extends LifecycleCapability {
constructor() {
super("echo-sockets");
}
onWebSocketUpgrade({ request }) {
if (!new URL(request.url).pathname.endsWith("/echo")) return;
const { 0: client, 1: server } = new WebSocketPair();
server.serializeAttachment({ owner: TAG });
this.lifecycle.sockets.accept(server, [TAG]);
return new Response(null, { status: 101, webSocket: client });
}
onWebSocketMessage(ws, message) {
if (!this.#owns(ws)) return false;
ws.send(message);
return true;
}
onWebSocketClose(ws, code, reason) {
if (!this.#owns(ws)) return false;
ws.close(code, reason);
return true;
}
get connectionCount() {
return this.lifecycle.sockets.get(TAG).length;
}
#owns(ws) {
const attachment = ws.deserializeAttachment();
return attachment?.owner === TAG;
}
}import {
LifecycleCapability,
type CapabilityWebSocketUpgradeContext,
type WSMessage,
} from "agents/lifecycle";
const TAG = "echo";
export class EchoSockets extends LifecycleCapability {
constructor() {
super("echo-sockets");
}
onWebSocketUpgrade({
request,
}: CapabilityWebSocketUpgradeContext): Response | undefined {
if (!new URL(request.url).pathname.endsWith("/echo")) return;
const { 0: client, 1: server } = new WebSocketPair();
server.serializeAttachment({ owner: TAG });
this.lifecycle.sockets.accept(server, [TAG]);
return new Response(null, { status: 101, webSocket: client });
}
onWebSocketMessage(ws: WebSocket, message: WSMessage): boolean {
if (!this.#owns(ws)) return false;
ws.send(message);
return true;
}
onWebSocketClose(ws: WebSocket, code: number, reason: string): boolean {
if (!this.#owns(ws)) return false;
ws.close(code, reason);
return true;
}
get connectionCount(): number {
return this.lifecycle.sockets.get(TAG).length;
}
#owns(ws: WebSocket): boolean {
const attachment = ws.deserializeAttachment() as { owner?: string } | null;
return attachment?.owner === TAG;
}
}EchoSockets can sit beside the WebSockets capability. WebSockets is a catch-all for upgrades, so the Lifecycle offers each upgrade to EchoSockets first, whatever the install order. For most real-time clients, use the WebSockets capability instead.
The job types are described on Jobs and alarms:
LifecycleJobs: refer to Manage jobs.LifecycleJobPushOptions: refer to Push options.LifecycleJob: refer to TheLifecycleJobshape.LifecycleJobOutcome: refer to Control what happens after a job runs.MemoryLimitContext: refer to Memory-limit protection.
agents/lifecycle defines the connection types, so that both the WebSockets capability and getCurrentAgent() can use them:
| Type | Description |
|---|---|
Connection<TState> |
A WebSocket with id, uri (the upgrade URL), read-only state, setState(), and tags. The first tag is always the connection ID. |
ConnectionContext |
{ request: Request }, the original upgrade request. |
ConnectionState<T> |
Immutable connection state, or null. Stored in the socket's hibernation attachment. |
ConnectionSetStateFn<T> |
(prevState: ConnectionState<T>) => T, an updater for connection.setState(). |
WSMessage |
string | ArrayBuffer | ArrayBufferView. |
For how connections work, refer to WebSockets.
getCurrentAgent<Host>() returns a CurrentAgentContext<Host> with agent, connection, request, and email. For more information, refer to getCurrentAgent().