Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/content/docs/agents/api-reference/schedule-tasks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ An Agent can schedule tasks to be run in the future by calling `this.schedule(wh

Scheduled tasks can do anything a request or message from a user can: make requests, query databases, send emails, read+write state: scheduled tasks can invoke any regular method on your Agent.

:::note[Calling destroy() in scheduled tasks]

You can safely call `this.destroy()` within a scheduled task callback. The Agent will properly handle cleanup and eviction, skipping any remaining database updates after the destroy flag is set.

:::

### Scheduling tasks

You can call `this.schedule` within any method on an Agent, and schedule tens-of-thousands of tasks per individual Agent:
Expand Down Expand Up @@ -48,6 +54,9 @@ You can schedule tasks in multiple ways:
<TypeScriptExample>

```ts
// schedule a task to run immediately
let task = await this.schedule(0, "someTask", { message: "hello" });

// schedule a task to run in 10 seconds
let task = await this.schedule(10, "someTask", { message: "hello" });

Expand All @@ -74,6 +83,12 @@ Each task is mapped to a row in the Agent's underlying [SQLite database](/durabl

:::

:::note[Destroying an Agent from a scheduled task]

You can safely call `this.destroy()` from within a scheduled task callback. The Agent SDK handles this scenario by setting an internal flag to prevent database updates after destruction and deferring the context abort to allow the alarm handler to complete cleanly. This prevents errors that would otherwise occur when the alarm handler attempts to update the schedule table after storage has been cleared.

:::

### Managing scheduled tasks

You can get, cancel and filter across scheduled tasks within an Agent using the scheduling API:
Expand Down Expand Up @@ -104,3 +119,40 @@ let tasks = this.getSchedules({
```

</TypeScriptExample>

### Lifecycle management with scheduled tasks

When working with scheduled tasks, you can safely call `this.destroy()` from within a scheduled callback to terminate the Agent instance after completing a task. The Agent SDK properly handles the cleanup process to ensure scheduled tasks complete successfully before the Agent is evicted.

<TypeScriptExample>

```ts
export class SchedulingAgent extends Agent {
async onRequest(request) {
// Schedule a self-destructing task
await this.schedule(60, "cleanupAndDestroy");
return new Response("Agent will self-destruct in 60 seconds");
}

async cleanupAndDestroy(data) {
// Perform final cleanup operations
await this.sendEmail({
to: "[email protected]",
subject: "Task completed",
body: "Agent task finished, shutting down"
});

// Safely destroy the Agent instance
// The destroy operation will complete after this callback finishes
await this.destroy();
}
}
```

</TypeScriptExample>

:::note

When `destroy()` is called from within a scheduled task, the Agent SDK defers the destruction to ensure the scheduled callback completes successfully. The Agent instance will be evicted immediately after the callback finishes executing.

:::
23 changes: 22 additions & 1 deletion src/content/docs/agents/concepts/agent-class.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,11 @@ class MyAgent extends Agent {

### `this.destroy`

`this.destroy()` drops all tables, deletes alarms, clears storage, and aborts the context. To ensure that the Durable Object is fully evicted, `this.ctx.abort()` is called, which throws an uncatchable error that will show up in your logs (read more about it in [abort()](/durable-objects/api/state/#abort)).
`this.destroy()` drops all tables, deletes alarms, clears storage, and aborts the context. To ensure that the Durable Object is fully evicted, `this.ctx.abort()` is called asynchronously using `setTimeout()` to allow any currently executing handlers (like scheduled tasks) to complete their cleanup operations before the context is aborted.

This means `this.ctx.abort()` throws an uncatchable error that will show up in your logs, but it does so after yielding to the event loop (read more about it in [abort()](/durable-objects/api/state/#abort)).

The `destroy()` method can be safely called within scheduled tasks. When called from within a schedule callback, the Agent sets an internal flag to skip any remaining database updates, and yields `ctx.abort()` to the event loop to ensure the alarm handler completes cleanly before the Agent is evicted.

```ts
class MyAgent extends Agent {
Expand All @@ -443,9 +447,26 @@ class MyAgent extends Agent {
// This wipes everything!
await this.destroy();
}

async selfDestruct() {
// Safe to call from within a scheduled task
await this.schedule(60, "destroyAfterDelay", {});
}

async destroyAfterDelay() {
// This will safely destroy the Agent even when
// called from within the alarm handler
await this.destroy();
}
}
```

:::note[Using destroy() in scheduled tasks]

You can safely call `this.destroy()` from within a scheduled task callback. The Agent SDK sets an internal flag to prevent database updates after destruction and defers the context abort to ensure the alarm handler completes cleanly.

:::

### Routing

The `Agent` class re-exports PartyKit's [addressing helpers](#addressing) as `getAgentByName` and `routeAgentRequest`.
Expand Down
Loading