> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt
> Use this file to discover all available pages before exploring further.

# Scheduling

> Schedule callbacks to run at future times or on recurring intervals

## Overview

Agents provide built-in task scheduling with support for one-time tasks, delayed execution, cron-based schedules, and fixed intervals. Schedules persist across hibernation and support automatic retry on failure.

```typescript theme={null}
import { Agent, callable } from "agents";

class TaskAgent extends Agent {
  async onStart() {
    // Schedule a daily backup at midnight
    await this.schedule("dailyBackup", {
      cron: "0 0 * * *"
    });
  }

  async dailyBackup() {
    console.log("Running daily backup...");
    // Backup logic
  }
}
```

## schedule()

Schedule a callback to run at a future time or on a recurring interval.

<ParamField path="callback" type="keyof this" required>
  Name of the method to call
</ParamField>

<ParamField path="options" type="ScheduleOptions" required>
  Schedule configuration (see variants below)
</ParamField>

**Returns:** `Promise<string>` - Schedule ID

## Schedule Types

### One-Time (Specific Time)

Execute a callback at a specific date/time.

<ParamField path="time" type="Date" required>
  Date/time to execute
</ParamField>

<ParamField path="payload" type="T">
  Data to pass to the callback
</ParamField>

<ParamField path="retry" type="RetryOptions">
  Retry options for this schedule
</ParamField>

```typescript theme={null}
// Schedule for tomorrow at 2 PM
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(14, 0, 0, 0);

await this.schedule("sendReminder", {
  time: tomorrow,
  payload: { userId: "123", type: "subscription" }
});
```

### Delayed Execution

Execute a callback after a delay (in seconds).

<ParamField path="delayInSeconds" type="number" required>
  Number of seconds to delay
</ParamField>

<ParamField path="payload" type="T">
  Data to pass to the callback
</ParamField>

<ParamField path="retry" type="RetryOptions">
  Retry options for this schedule
</ParamField>

```typescript theme={null}
// Schedule to run in 1 hour
await this.schedule("processUpload", {
  delayInSeconds: 3600,
  payload: { fileId: "abc123" }
});

// Schedule to run in 30 seconds
await this.schedule("quickTask", {
  delayInSeconds: 30
});
```

### Cron Schedule

Execute a callback on a recurring schedule using cron syntax.

<ParamField path="cron" type="string" required>
  Cron expression (e.g., "0 0 \* \* \*")
</ParamField>

<ParamField path="payload" type="T">
  Data to pass to the callback
</ParamField>

<ParamField path="retry" type="RetryOptions">
  Retry options for this schedule
</ParamField>

```typescript theme={null}
// Every day at midnight
await this.schedule("dailyBackup", {
  cron: "0 0 * * *"
});

// Every Monday at 9 AM
await this.schedule("weeklyReport", {
  cron: "0 9 * * 1",
  payload: { reportType: "weekly" }
});

// Every 15 minutes
await this.schedule("healthCheck", {
  cron: "*/15 * * * *"
});
```

**Cron Format:** `minute hour day month weekday`

* `*` = any value
* `*/n` = every n units
* `0-6` = Sunday through Saturday (for weekday)

### Interval

Execute a callback at fixed intervals (in seconds).

<ParamField path="intervalSeconds" type="number" required>
  Number of seconds between executions
</ParamField>

<ParamField path="payload" type="T">
  Data to pass to the callback
</ParamField>

<ParamField path="retry" type="RetryOptions">
  Retry options for this schedule
</ParamField>

```typescript theme={null}
// Every 5 minutes
await this.schedule("syncData", {
  intervalSeconds: 300
});

// Every hour
await this.schedule("generateReport", {
  intervalSeconds: 3600,
  payload: { reportType: "hourly" }
});
```

<Note>
  Interval schedules are resilient to hung executions. If a callback takes longer than `hungScheduleTimeoutSeconds` (default: 30s), the interval is reset.
</Note>

## Callback Implementation

Scheduled callbacks receive the payload (if provided):

```typescript theme={null}
class TaskAgent extends Agent<Env, State> {
  async onStart() {
    await this.schedule("processTask", {
      time: new Date(Date.now() + 3600000),
      payload: { taskId: "123", priority: "high" }
    });
  }

  async processTask(payload: { taskId: string; priority: string }) {
    console.log(`Processing task ${payload.taskId} with priority ${payload.priority}`);
    // Task logic
  }
}
```

## Retry Options

Schedules support automatic retry on failure:

<ParamField path="retry" type="RetryOptions">
  <ParamField path="maxAttempts" type="number" default="3">
    Maximum number of retry attempts
  </ParamField>

  <ParamField path="baseDelayMs" type="number" default="100">
    Base delay in milliseconds for exponential backoff
  </ParamField>

  <ParamField path="maxDelayMs" type="number" default="3000">
    Maximum delay cap in milliseconds
  </ParamField>
</ParamField>

```typescript theme={null}
await this.schedule("unreliableTask", {
  delayInSeconds: 60,
  retry: {
    maxAttempts: 5,
    baseDelayMs: 200,
    maxDelayMs: 5000
  }
});
```

<Note>
  Retry options can also be configured globally via static `options.retry` on the Agent class.
</Note>

## Managing Schedules

### getSchedules()

Query existing schedules.

```typescript theme={null}
const schedules = this.sql<Schedule>`
  SELECT * FROM cf_agents_schedules
  WHERE callback = 'dailyBackup'
`;

for (const schedule of schedules) {
  console.log(`Schedule ${schedule.id}: ${schedule.type}`);
}
```

### cancelSchedule()

Cancel a scheduled task.

```typescript theme={null}
const scheduleId = await this.schedule("task", { delayInSeconds: 60 });

// Cancel it
this.sql`DELETE FROM cf_agents_schedules WHERE id = ${scheduleId}`;
```

### updateSchedule()

Update a schedule's payload or timing:

```typescript theme={null}
this.sql`
  UPDATE cf_agents_schedules
  SET payload = ${JSON.stringify(newPayload)}
  WHERE id = ${scheduleId}
`;
```

## Queue vs Schedule

### queue()

For immediate asynchronous execution:

```typescript theme={null}
// Execute as soon as possible
await this.queue("processUpload", {
  fileId: "abc123"
});
```

**When to use:**

* Immediate background tasks
* Fire-and-forget operations
* No specific timing requirements

### schedule()

For time-based or recurring execution:

```typescript theme={null}
// Execute at a specific time
await this.schedule("sendEmail", {
  time: scheduledDate,
  payload: { to: "user@example.com" }
});
```

**When to use:**

* Time-based tasks
* Recurring operations
* Delayed execution

## Natural Language Scheduling

Use AI to parse natural language schedule requests:

```typescript theme={null}
import { generateObject } from "ai";
import { scheduleSchema, getSchedulePrompt } from "agents/schedule";

@callable()
async scheduleTask(userInput: string) {
  const result = await generateObject({
    model: this.env.AI.run("@cf/meta/llama-3.3-70b-instruct-fp8-fast"),
    prompt: `${getSchedulePrompt({ date: new Date() })} Input: "${userInput}"`,
    schema: scheduleSchema,
    providerOptions: {
      openai: { strictJsonSchema: false }
    }
  });

  const { description, when } = result.object;

  switch (when.type) {
    case "scheduled":
      await this.schedule("executeTask", {
        time: new Date(when.date),
        payload: { description }
      });
      break;
    case "delayed":
      await this.schedule("executeTask", {
        delayInSeconds: when.delayInSeconds,
        payload: { description }
      });
      break;
    case "cron":
      await this.schedule("executeTask", {
        cron: when.cron,
        payload: { description }
      });
      break;
  }

  return `Scheduled: ${description}`;
}
```

**Example inputs:**

* "Backup database every day at midnight"
* "Send report tomorrow at 2 PM"
* "Run health check every 15 minutes"

## Persistence

Schedules are stored in SQLite:

```sql theme={null}
CREATE TABLE cf_agents_schedules (
  id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),
  callback TEXT,
  payload TEXT,
  type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron', 'interval')),
  time INTEGER,
  delayInSeconds INTEGER,
  cron TEXT,
  intervalSeconds INTEGER,
  running INTEGER DEFAULT 0,
  retry_options TEXT,
  created_at INTEGER DEFAULT (unixepoch())
);
```

Schedules survive Agent hibernation and are automatically restored on wake.

## Best Practices

### Keep Callbacks Small

```typescript theme={null}
// ✅ Good - focused callback
async dailyBackup() {
  const data = await this.fetchData();
  await this.sendToBackup(data);
}

// ❌ Bad - too much logic
async dailyBackup() {
  // 100 lines of backup logic
}
```

### Use Payloads for Context

```typescript theme={null}
// ✅ Good - payload provides context
await this.schedule("processOrder", {
  delayInSeconds: 3600,
  payload: { orderId: "123", customerId: "456" }
});

async processOrder(payload: { orderId: string; customerId: string }) {
  const order = await this.fetchOrder(payload.orderId);
  // ...
}

// ❌ Bad - no context
await this.schedule("processOrder", {
  delayInSeconds: 3600
});
```

### Handle Failures

```typescript theme={null}
async unreliableTask(payload: unknown) {
  try {
    await this.externalAPI.call(payload);
  } catch (error) {
    console.error("Task failed:", error);
    // Retry is automatic if retry options are set
    throw error;
  }
}
```

### Use Cron for Recurring Tasks

```typescript theme={null}
// ✅ Good - cron for daily task
await this.schedule("dailyReport", {
  cron: "0 9 * * *" // 9 AM every day
});

// ❌ Bad - manually scheduling daily
for (let i = 0; i < 365; i++) {
  const date = new Date();
  date.setDate(date.getDate() + i);
  await this.schedule("dailyReport", { time: date });
}
```

## Related

* [Agent Class](/api/agent-class) - Agent base class
* [Natural Language Scheduling](https://github.com/cloudflare/agents/tree/main/examples/scheduler) - Example
