Skip to main content

Scheduling Flights and managing runs

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.

note

Scheduled (cron) runs require a paid plan, which can be accessed by adding a credit card on Lite, or using Business or Enterprise. Without a credit card, Flights run on demand for Lite (with limits) customers. See Availability and plan limits for the full per-plan breakdown.

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.
note

On Lite (with limits), one Flight run executes at a time. For unlimited concurrent runs, add a credit card on Lite, or use Business or Enterprise plans. See Availability and plan limits.

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.