Airflow Workflow
Execution guide for the scheduler subagent working with Airflow.
Troubleshoot a Failed Job
- Check job status —
get_scheduler_job(job_id)
- List recent runs —
list_job_runs(job_id, limit=5) to find the failed run
- Get error log —
get_run_log(job_id, run_id) for the failed run_id
- Analyze the error — common failure categories:
- SQL syntax error → fix SQL and
update_job()
- Connection failure → check conn_id in Airflow Connections (Admin > Connections), verify host is reachable from the scheduler worker
- Timeout → optimize the query or increase resources
- Permission denied → verify DB credentials in Airflow Connections (Admin > Connections)
- Fix and re-run:
- Update SQL:
update_job(job_id, sql_file_path=..., job_name=..., conn_id=...)
- Manual trigger to verify:
trigger_scheduler_job(job_id)
- Confirm success:
list_job_runs(job_id, limit=1)
Update an Existing Job
- Check current state —
get_scheduler_job(job_id) to see existing config
- Pause the job —
pause_job(job_id) to prevent runs during update
- Write SQL — use
write_file or edit_file to save the new SQL under
jobs/<job_name>.sql
- Update —
update_job(job_id, sql_file_path=..., job_name=..., conn_id=...)
- Resume —
resume_job(job_id) to re-enable scheduling
- Do not manually trigger after a normal create/update unless the user
explicitly asks for an immediate run. Deterministic validation triggers and
polls deliverable scheduler jobs after the agent returns the target.
Delete an Existing Job
- Confirm with the user — deletion is destructive.
- Delete — call
delete_job(job_id).
- Honor the tool result — if
delete_job returns success=0, report the
deletion as failed or incomplete. Do not claim completion or success.
- Verify only with direct lookup — use
get_scheduler_job(job_id) if you
need a follow-up check. For Airflow, scheduling deletion is complete when
the job is not found or is inactive/deleted.
- Do not rely on list output —
list_scheduler_jobs may omit an Airflow DAG
after its file is removed even while Airflow metadata still exists and blocks
re-creation with the same job id.
- Use precise wording for partial cleanup — if metadata still exists but
the DAG is inactive/deleted, say scheduling has been removed and metadata
cleanup is pending. The same
dag_id may not be immediately reusable via
submit; use update or retry cleanup if needed.
- Use explicit file deletion only —
delete_job owns Airflow DAG file
removal. For other files, use a dedicated delete-file tool if one is
available; otherwise report that file deletion is unavailable. Do not
overwrite or empty files as a substitute for deletion.
DB Connection (conn_id)
submit_sql_job and update_job require conn_id — the Airflow Connection ID for the target database.
The connection is managed entirely by Airflow (Admin > Connections) and resolved at runtime by the scheduler worker.
Available conn_id values are shown in the submit_sql_job and update_job tool descriptions (from scheduler.connections in agent.yml).
Naming Conventions
job_name: <frequency>_<domain>_<description>, e.g. daily_sales_summary, hourly_order_count
- SQL file:
jobs/<job_name>.sql
Before calling submit_sql_job or update_job, create or update that SQL
file with write_file / edit_file. Do not ask the user to create the file
when filesystem tools are available.
Common Cron Expressions
| Schedule |
Cron |
| Every day at 8am |
0 8 * * * |
| Every hour |
0 * * * * |
| Every 2 hours |
0 */2 * * * |
| Monday at 9am |
0 9 * * 1 |
| 1st of month at midnight |
0 0 1 * * |
Quick Reference
| Goal |
Tool |
| Create SQL file |
write_file(path="jobs/<job_name>.sql", content=...) |
| Submit SQL job |
submit_sql_job(job_name, sql_file_path, conn_id) |
| Submit SparkSQL job |
submit_sparksql_job(job_name, sql_file_path) |
| Check job status |
get_scheduler_job(job_id) |
| List all jobs |
list_scheduler_jobs(limit=20) |
| Trigger manual run |
trigger_scheduler_job(job_id) only when explicitly requested or troubleshooting |
| View run history |
list_job_runs(job_id) |
| View run log |
get_run_log(job_id, run_id) |
| Pause / Resume |
pause_job(job_id) / resume_job(job_id) |
| Update job |
update_job(job_id, sql_file_path, job_name, conn_id) |
| Delete job |
delete_job(job_id) |
1---2name: airflow-workflow3description: Execution guide for Airflow scheduled jobs — troubleshooting, updating, conn_id conventions, and cron references4---56# Airflow Workflow78Execution guide for the scheduler subagent working with Airflow.910## Troubleshoot a Failed Job11121. **Check job status** — `get_scheduler_job(job_id)`132. **List recent runs** — `list_job_runs(job_id, limit=5)` to find the failed run143. **Get error log** — `get_run_log(job_id, run_id)` for the failed run_id154. **Analyze the error** — common failure categories:16 - SQL syntax error → fix SQL and `update_job()`17 - Connection failure → check conn_id in Airflow Connections (Admin > Connections), verify host is reachable from the scheduler worker18 - Timeout → optimize the query or increase resources19 - Permission denied → verify DB credentials in Airflow Connections (Admin > Connections)205. **Fix and re-run**:21 - Update SQL: `update_job(job_id, sql_file_path=..., job_name=..., conn_id=...)`22 - Manual trigger to verify: `trigger_scheduler_job(job_id)`23 - Confirm success: `list_job_runs(job_id, limit=1)`2425## Update an Existing Job26271. **Check current state** — `get_scheduler_job(job_id)` to see existing config282. **Pause the job** — `pause_job(job_id)` to prevent runs during update293. **Write SQL** — use `write_file` or `edit_file` to save the new SQL under30 `jobs/<job_name>.sql`314. **Update** — `update_job(job_id, sql_file_path=..., job_name=..., conn_id=...)`325. **Resume** — `resume_job(job_id)` to re-enable scheduling336. **Do not manually trigger** after a normal create/update unless the user34 explicitly asks for an immediate run. Deterministic validation triggers and35 polls deliverable scheduler jobs after the agent returns the target.3637## Delete an Existing Job38391. **Confirm with the user** — deletion is destructive.402. **Delete** — call `delete_job(job_id)`.413. **Honor the tool result** — if `delete_job` returns `success=0`, report the42 deletion as failed or incomplete. Do not claim completion or success.434. **Verify only with direct lookup** — use `get_scheduler_job(job_id)` if you44 need a follow-up check. For Airflow, scheduling deletion is complete when45 the job is not found or is inactive/deleted.465. **Do not rely on list output** — `list_scheduler_jobs` may omit an Airflow DAG47 after its file is removed even while Airflow metadata still exists and blocks48 re-creation with the same job id.496. **Use precise wording for partial cleanup** — if metadata still exists but50 the DAG is inactive/deleted, say scheduling has been removed and metadata51 cleanup is pending. The same `dag_id` may not be immediately reusable via52 submit; use update or retry cleanup if needed.537. **Use explicit file deletion only** — `delete_job` owns Airflow DAG file54 removal. For other files, use a dedicated delete-file tool if one is55 available; otherwise report that file deletion is unavailable. Do not56 overwrite or empty files as a substitute for deletion.5758## DB Connection (`conn_id`)5960`submit_sql_job` and `update_job` require `conn_id` — the Airflow Connection ID for the target database.61The connection is managed entirely by Airflow (Admin > Connections) and resolved at runtime by the scheduler worker.6263Available conn_id values are shown in the `submit_sql_job` and `update_job` tool descriptions (from `scheduler.connections` in agent.yml).6465## Naming Conventions6667- `job_name`: `<frequency>_<domain>_<description>`, e.g. `daily_sales_summary`, `hourly_order_count`68- SQL file: `jobs/<job_name>.sql`6970Before calling `submit_sql_job` or `update_job`, create or update that SQL71file with `write_file` / `edit_file`. Do not ask the user to create the file72when filesystem tools are available.7374## Common Cron Expressions7576| Schedule | Cron |77|----------|------|78| Every day at 8am | `0 8 * * *` |79| Every hour | `0 * * * *` |80| Every 2 hours | `0 */2 * * *` |81| Monday at 9am | `0 9 * * 1` |82| 1st of month at midnight | `0 0 1 * *` |8384## Quick Reference8586| Goal | Tool |87|------|------|88| Create SQL file | `write_file(path="jobs/<job_name>.sql", content=...)` |89| Submit SQL job | `submit_sql_job(job_name, sql_file_path, conn_id)` |90| Submit SparkSQL job | `submit_sparksql_job(job_name, sql_file_path)` |91| Check job status | `get_scheduler_job(job_id)` |92| List all jobs | `list_scheduler_jobs(limit=20)` |93| Trigger manual run | `trigger_scheduler_job(job_id)` only when explicitly requested or troubleshooting |94| View run history | `list_job_runs(job_id)` |95| View run log | `get_run_log(job_id, run_id)` |96| Pause / Resume | `pause_job(job_id)` / `resume_job(job_id)` |97| Update job | `update_job(job_id, sql_file_path, job_name, conn_id)` |98| Delete job | `delete_job(job_id)` |