Skip to main content

Scheduling Flights and managing runs

Preview
This feature is in preview and is subject to change.

A Flight runs on demand, on a schedule, or both. This page covers cron syntax, manual triggers, the run lifecycle, and cancellation.

Cron syntax

Schedules use a standard 5-field cron expression. All times are in UTC.

* * * * *
│ │ │ │ │
│ │ │ │ └── day of week (0-6, Sunday is 0)
│ │ │ └──── month (1-12)
│ │ └────── day of month (1-31)
│ └──────── hour (0-23)
└────────── minute (0-59)

Common cadences:

CronWhen it fires
*/15 * * * *Every 15 minutes
0 * * * *Hourly at :00
0 6 * * *Daily at 06:00 UTC
0 6 * * 1Every Monday at 06:00 UTC
0 0 1 * *First of the month at 00:00 UTC

You can set the schedule in the UI under the Schedule panel, through the MCP create_flight or update_flight tools, or through SQL on MD_CREATE_FLIGHT / MD_UPDATE_FLIGHT. Omit schedule_cron to make the Flight on-demand only.

Changing or clearing a schedule

Update the cron expression with MD_UPDATE_FLIGHT when the cadence changes:

CALL MD_UPDATE_FLIGHT(
flight_id := '<flight_id>',
schedule_cron := '0 7 * * *'
);

To stop the schedule from firing, pass schedule_cron := '' (empty string) to update_flight or MD_UPDATE_FLIGHT. The Flight reverts to on-demand only.

CALL MD_UPDATE_FLIGHT(
flight_id := '<flight_id>',
schedule_cron := ''
);

In the UI, clearing the cron expression has the same effect.

Triggering an on-demand run

You can run any Flight manually, with or without a schedule.

Ask your AI agent to trigger the run. The MCP tool is run_flight:

"Run the heartbeat Flight and show me the logs when it finishes."

The agent calls run_flight, then polls list_flight_runs and get_flight_run_logs until the run reaches a terminal state.

run_flight returns immediately with a new run in RUN_STATUS_PENDING. The run is asynchronous: poll for completion.

Override config for a single run

Pass a config map to MD_RUN_FLIGHT to override stored config values for one run, without editing the Flight or creating a version. You can only set keys the Flight already defines:

CALL MD_RUN_FLIGHT(
flight_id := '<flight_id>',
config := MAP {'LOAD_PARTITION': '2024'}
);

Each run records the config it used, visible in the config column of MD_LIST_FLIGHT_RUNS. See Authentication, config, and secrets for the full pattern.

The run lifecycle

StatusMeaning
RUN_STATUS_PENDINGThe run is queued and waiting for a runtime to start.
RUN_STATUS_RUNNINGThe runtime is executing main().
RUN_STATUS_SUCCEEDEDmain() returned without raising.
RUN_STATUS_FAILEDmain() raised or the runtime reported a failure.
RUN_STATUS_CANCELLEDThe run was cancelled before completion.

Watching for completion

Runs are asynchronous, so triggering one doesn't block. Poll for the latest runs through the MCP list_flight_runs tool, through SQL with MD_LIST_FLIGHT_RUNS, or through the UI's Runs panel. Runs are returned newest first.

SELECT run_number, status, flight_version, created_at
FROM MD_LIST_FLIGHT_RUNS(flight_id := '<flight_id>')
ORDER BY run_number DESC
LIMIT 10;

To read combined stdout and stderr for a single run, use get_flight_run_logs (MCP) or MD_GET_FLIGHT_LOGS (SQL). When the log is large, the response is the tail.

Cancelling a run

You can cancel a run that's still RUN_STATUS_PENDING or RUN_STATUS_RUNNING:

  • UI: open the run, then click Cancel run.
  • MCP: cancel_flight_run(flight_id, run_number).
  • SQL: CALL MD_CANCEL_FLIGHT_RUN(flight_id := '<flight_id>', run_number := <n>);

Cancelling a run that's already in a terminal status (RUN_STATUS_SUCCEEDED, RUN_STATUS_FAILED, RUN_STATUS_CANCELLED) returns an error.

Time zones

Schedules are always in UTC. The MotherDuck UI shows a local time / UTC toggle on the Runs panel so you can read timestamps in your local zone, but the cron expression itself is interpreted in UTC.

If you need a Flight to fire at 09:00 in a non-UTC zone, do the conversion when you set the schedule. For example, 09:00 in Amsterdam during summer time (CEST, UTC+2) is 0 7 * * * in cron.

Versions and in-flight runs

When a run starts, it locks to the Flight version that was current at that moment. If you update the Flight while a run is in progress, the in-progress run finishes against the version it started with; only the next run picks up the updated source.

This means a long-running Flight is always reproducible against a specific version: you can find that version through list_flight_versions or MD_LIST_FLIGHT_VERSIONS and inspect the exact source code it ran.