{
  "license": "CC BY 4.0",
  "licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
  "recipe": {
    "slug": "find-stalled-background-jobs",
    "title": "Find Stalled Background Jobs With SQL",
    "testedWith": "Apache DataFusion 45.2.0",
    "lastReviewed": "2026-07-27"
  },
  "contract": {
    "tableName": "job_events",
    "schema": [
      {
        "name": "timestamp_utc",
        "type": "Timestamp",
        "description": "When the event occurred."
      },
      {
        "name": "job_id",
        "type": "Utf8",
        "description": "Identifier shared by every event for one job."
      },
      {
        "name": "job_name",
        "type": "Utf8",
        "description": "Stable logical job name."
      },
      {
        "name": "event_name",
        "type": "Utf8",
        "description": "job_started, job_completed, or job_failed."
      },
      {
        "name": "queue_name",
        "type": "Utf8",
        "description": "Queue that owns the job."
      }
    ]
  },
  "query": "WITH started AS (\n  SELECT\n    job_id,\n    job_name,\n    queue_name,\n    MIN(timestamp_utc) AS started_at\n  FROM job_events\n  WHERE event_name = 'job_started'\n    AND timestamp_utc >= now() - INTERVAL '24 hours'\n  GROUP BY job_id, job_name, queue_name\n),\nfinished AS (\n  SELECT\n    job_id,\n    MAX(timestamp_utc) AS finished_at\n  FROM job_events\n  WHERE event_name IN ('job_completed', 'job_failed')\n    AND timestamp_utc >= now() - INTERVAL '24 hours'\n  GROUP BY job_id\n)\nSELECT\n  s.job_id,\n  s.job_name,\n  s.queue_name,\n  s.started_at\nFROM started s\nLEFT JOIN finished f ON s.job_id = f.job_id\nWHERE f.job_id IS NULL\n  AND s.started_at < now() - INTERVAL '15 minutes'\nORDER BY s.started_at ASC;",
  "fixtureKind": "schema-example",
  "inputRows": [
    {
      "timestamp_utc": "2026-07-28T10:00:00Z",
      "job_id": "job_id_example_1",
      "job_name": "job_name_example_1",
      "event_name": "workflow_completed",
      "queue_name": "queue_name_example_1"
    },
    {
      "timestamp_utc": "2026-07-28T11:00:00Z",
      "job_id": "job_id_example_2",
      "job_name": "job_name_example_2",
      "event_name": "workflow_completed",
      "queue_name": "queue_name_example_2"
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00Z",
      "job_id": "job_id_example_3",
      "job_name": "job_name_example_3",
      "event_name": "workflow_completed",
      "queue_name": "queue_name_example_3"
    }
  ],
  "illustrativeInputRows": [
    {
      "timestamp_utc": "2026-07-28T10:00:00Z",
      "job_id": "job_id_example_1",
      "job_name": "job_name_example_1",
      "event_name": "workflow_completed",
      "queue_name": "queue_name_example_1"
    },
    {
      "timestamp_utc": "2026-07-28T11:00:00Z",
      "job_id": "job_id_example_2",
      "job_name": "job_name_example_2",
      "event_name": "workflow_completed",
      "queue_name": "queue_name_example_2"
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00Z",
      "job_id": "job_id_example_3",
      "job_name": "job_name_example_3",
      "event_name": "workflow_completed",
      "queue_name": "queue_name_example_3"
    }
  ],
  "expectedOutput": {
    "columns": [
      "job_id",
      "job_name",
      "queue_name",
      "started_at"
    ],
    "rows": [
      {
        "job_id": "job_7f31",
        "job_name": "import_catalog",
        "queue_name": "imports",
        "started_at": "2026-07-27 15:02:11Z"
      },
      {
        "job_id": "job_801c",
        "job_name": "sync_subscription",
        "queue_name": "billing",
        "started_at": "2026-07-27 15:19:43Z"
      }
    ]
  },
  "notes": [
    "The compact input rows demonstrate field names and JSON types; they are not claimed to generate the displayed aggregate by themselves.",
    "The expected output is deterministic synthetic review data for the documented output shape.",
    "Adapt time windows, thresholds, identities, and business definitions before operational use."
  ]
}