import { snippets } from "@/lib/generated/snippets";
import { Snippet } from "@/components/code";
import { Callout, Card, Cards, Steps, Tabs } from "nextra/components";
import UniversalTabs from "@/components/UniversalTabs";

# Scheduled Runs

Scheduled runs allow you to trigger a task at a specific time in the future. Some example use cases of scheduling runs might include:

- Sending a reminder email at a specific time after a user took an action.
- Running a one-time maintenance task at a predetermined time as determined by your application. For instance, you might want to run a database vacuum during a maintenance window any time a task matches a certain criteria.
- Allowing a customer to decide when they want your application to perform a specific task. For instance, if your application is a simple alarm app that sends a customer a notification at a time that they specify, you might create a scheduled run for each alarm that the customer sets.

Hatchet supports scheduled runs to run on a schedule defined in a few different ways:

- [Programmatically](/v1/scheduled-runs#programmatically-creating-scheduled-runs): Use the Hatchet SDKs to dynamically set the schedule of a task.
- [Hatchet Dashboard](/v1/scheduled-runs#managing-scheduled-runs-in-the-hatchet-dashboard): Manually create scheduled runs from the Hatchet Dashboard.

<Callout type="warning">
  The scheduled time is when Hatchet **enqueues** the task, not when the run
  starts. Scheduling constraints like concurrency limits, rate limits, and retry
  policies can affect run start times.
</Callout>

## Programmatically Creating Scheduled Runs

### Create a Scheduled Run

You can create dynamic scheduled runs programmatically via the API to run tasks at a specific time in the future.

Here's an example of creating a scheduled run to trigger a task tomorrow at noon:

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]}>
  <Tabs.Tab title="Python">

<Snippet src={snippets.python.simple.schedule.schedule_a_task} />

</Tabs.Tab>
<Tabs.Tab title="Typescript">
<Snippet src={snippets.typescript.simple.schedule.create_a_scheduled_run} />
</Tabs.Tab>
<Tabs.Tab title="Go">
<Snippet src={snippets.go.scheduled.main.create} />
</Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.simple.schedule.schedule_a_task} />
  </Tabs.Tab>
</UniversalTabs>

In this example you can have different scheduled times for different customers, or dynamically set the scheduled time based on some other business logic.

When creating a scheduled run via the API, you will receive a scheduled run object with a metadata property containing the id of the scheduled run. This id can be used to reference the scheduled run when deleting the scheduled run and is often stored in a database or other persistence layer.

<Callout type="info">
  Note: Be mindful of the time zone of the scheduled run. Scheduled runs are
  **always** stored and returned in UTC.
</Callout>

### Deleting a Scheduled Run

You can delete a scheduled run by calling the `delete` method on the scheduled client.

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]} variant="hidden">
  <Tabs.Tab title="Python">
    <Snippet src={snippets.python.scheduled.programatic_sync.delete} />
  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <Snippet src={snippets.typescript.simple.schedule.delete_a_scheduled_run} />
  </Tabs.Tab>
  <Tabs.Tab title="Go">
    <Snippet src={snippets.go.scheduled.main.delete} />
  </Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.scheduled.programatic_sync.delete} />
  </Tabs.Tab>
</UniversalTabs>

### Listing Scheduled Runs

You can list all scheduled runs for a task by calling the `list` method on the scheduled client.

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]} variant="hidden">
  <Tabs.Tab title="Python">
    <Snippet src={snippets.python.scheduled.programatic_sync.list} />
  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <Snippet src={snippets.typescript.simple.schedule.list_scheduled_runs} />
  </Tabs.Tab>
  <Tabs.Tab title="Go">
    <Snippet src={snippets.go.scheduled.main.list} />
  </Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.scheduled.programatic_sync.list} />
  </Tabs.Tab>
</UniversalTabs>

### Rescheduling a Scheduled Run

If you need to change the trigger time for an existing scheduled run, you can reschedule it by updating its `triggerAt`.

<UniversalTabs items={["Python", "Typescript", "Ruby"]} variant="hidden">
  <Tabs.Tab title="Python">
    <Snippet src={snippets.python.scheduled.programatic_sync.reschedule} />

  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <Snippet
      src={snippets.typescript.simple.schedule.reschedule_a_scheduled_run}
    />

  </Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.scheduled.programatic_sync.reschedule} />
  </Tabs.Tab>
</UniversalTabs>

<Callout type="warning">
  You can only reschedule scheduled runs created via the API (not runs created
  via a code-defined schedule), and Hatchet may reject rescheduling if the run
  has already triggered.
</Callout>

### Bulk operations (delete / reschedule)

Hatchet supports bulk operations for scheduled runs. You can bulk delete scheduled runs, and you can bulk reschedule scheduled runs by providing a list of updates.

<UniversalTabs items={["Python", "Typescript", "Ruby"]} variant="hidden">
  <Tabs.Tab title="Python">
    <Snippet src={snippets.python.scheduled.programatic_sync.bulk_delete} />
    <Snippet src={snippets.python.scheduled.programatic_sync.bulk_reschedule} />

  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <Snippet src={snippets.typescript.simple.schedule.bulk_delete_scheduled_runs} />
    <Snippet
      src={snippets.typescript.simple.schedule.bulk_reschedule_scheduled_runs}
    />

  </Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.scheduled.programatic_sync.bulk_delete} />
    <Snippet src={snippets.ruby.scheduled.programatic_sync.bulk_reschedule} />
  </Tabs.Tab>
</UniversalTabs>

## Managing Scheduled Runs in the Hatchet Dashboard

In the Hatchet Dashboard, you can view and manage scheduled runs for your tasks.

Navigate to "Triggers" > "Scheduled Runs" in the left sidebar and click "Create Scheduled Run" at the top right.

You can specify run parameters such as Input, Additional Metadata, and the Scheduled Time.

![Create Scheduled Run](../../public/schedule-dash.gif)

You can also manage existing scheduled runs:

- **Single-run actions**: Use the per-row actions menu to **Reschedule** or **Delete** an individual scheduled run.
- **Bulk actions**: Use the **Actions** menu to bulk **Delete** or **Reschedule** either:
  - The selected rows, or
  - All rows matching the current filters (including “all” if no filters are set).

<Callout type="info">
  In the dashboard, reschedule/delete actions may be disabled for runs that were
  created via a code-defined schedule, and rescheduling may be disabled for runs
  that have already triggered.
</Callout>

## Scheduled Run Considerations

When using scheduled runs, there are a few considerations to keep in mind:

1. **Time Zone**: Scheduled runs are stored and returned in UTC. Make sure to consider the time zone when defining your scheduled time.

2. **Execution Time**: The actual execution time of a scheduled run may vary slightly from the scheduled time. Hatchet makes a best-effort attempt to enqueue the task as close to the scheduled time as possible, but there may be slight delays due to system load or other factors.

3. **Missed Schedules**: If a scheduled task is missed (e.g., due to system downtime), Hatchet will not automatically run the missed instances when the service comes back online.

4. **Overlapping Schedules**: If a task is still running when a second scheduled run is scheduled to start, Hatchet will start a new instance of the task or respect [concurrency](/v1/concurrency) policy.
