Schedule icon
Request icon
Return icon
Switch icon
Log icon
SlackIncomingWebhook icon

OpenAI Batch Job Sentinel

List recent OpenAI Batch API jobs every hour, change nothing, and alert Slack when a batch fails, expires or nears its 24-hour window unfinished.

Categories
AI

The OpenAI Batch API runs large jobs (embeddings for a whole catalog, nightly classification, evaluation sets) at half price, in exchange for a completion window of 24 hours. That trade has quiet failure modes: a batch fails validation because one line of the input file is malformed, a busy period means it is still in_progress when the window closes and it ends expired with only part of the results, or it completes but a share of its requests failed. The job that was waiting for the output file just finds nothing, often the next morning. This blueprint turns a scheduled, read-only call to the Batch API into a batch health gate: io.kestra.plugin.core.http.Request lists recent batches, one jq query finds failed, expired and at-risk batches and the failed-request share, and the result routes to a quiet log or a Slack alert.

How it works

  1. list_batches (io.kestra.plugin.core.http.Request) calls GET /v1/batches?limit=100 with a bearer API key. It is a read: no batch is created, canceled or changed, and no tokens are spent. Retries cover short network blips, and allowFailed plus allowFailure keep an API error from aborting the flow so it can be reported instead.
  2. summarize_batches (io.kestra.plugin.core.debug.Return) first guards for a missing or non-200 response (UNREACHABLE). Otherwise one jq query keeps batches whose created_at falls in the lookback window and lists those with status failed or expired (with the first validation error message), and those still validating, in_progress or finalizing with less than expiry_warning_hours left before expires_at. It adds up request_counts.total and request_counts.failed across completed batches. Any failed or expired batch, or a failed-request share at or above critical_failed_request_pct, is CRITICAL; an at-risk batch or a share at or above warning_failed_request_pct is WARNING; no batch in the window is LOW_VOLUME; otherwise HEALTHY.
  3. route_by_batch_health (io.kestra.plugin.core.flow.Switch) branches on that classification: HEALTHY and LOW_VOLUME log quietly, WARNING posts a Slack note, CRITICAL and UNREACHABLE page Slack. A defaults fallback logs anything unexpected.
  4. log_audit_result (io.kestra.plugin.core.log.Log) writes one audit line per run with the HTTP status and the full summary.
  5. The flow-level errors block pages Slack if the flow itself fails, and the hourly_check trigger runs at 10 minutes past every hour, shipped disabled: true.

What you get

  • An hourly, read-only check of every batch job with no custom scripting and no extra plugin to install.
  • A status output (HEALTHY / WARNING / CRITICAL / LOW_VOLUME / UNREACHABLE) other flows can gate on, for example to hold a downstream load until the batch results are complete, or to resubmit the failed lines.
  • Slack messages that name each failed, expired or at-risk batch with its endpoint, progress and hours left.
  • An audit line on every run, separate from Slack.

Who it's for

  • Data and ML teams that run embeddings, classification, extraction or evaluation jobs through the Batch API.
  • Teams that use Kestra to submit batches and want an independent check that they actually finished.
  • Anyone who has found an expired batch the morning after.

Why orchestrate this with Kestra

The OpenAI platform shows batches in a list, but nothing tells you a batch is about to miss its window or that 8% of its lines failed. Kestra turns a plain, read-only API call into a scheduled, typed classification with retries, a failure path and an execution history, and the status output lets the flows that consume batch results wait, retry or resubmit automatically.

Prerequisites

  • An OpenAI API key with read access to batches for the organization or project that submits them.
  • A Slack incoming webhook for the WARNING, CRITICAL, UNREACHABLE and flow-failure alerts.

Secrets

  • OPENAI_API_KEY: an API key (a project key is enough) for the project whose batches you want to watch.
  • SLACK_WEBHOOK: Slack incoming webhook used for every alert branch and the flow-failure alert.

In Kestra OSS, secrets are supplied as environment variables prefixed SECRET_ and base64-encoded, for example SECRET_OPENAI_API_KEY=$(echo -n 'sk-proj-xxxxxxxx' | base64), and read back with {{ secret('OPENAI_API_KEY') }}. Use the Enterprise secrets backend for encryption at rest and access control.

Quick start

  1. Submit a small batch (a few lines against /v1/chat/completions or /v1/embeddings), plus one with a malformed input file to produce a failed batch.
  2. Add OPENAI_API_KEY and SLACK_WEBHOOK as secrets.
  3. Run the flow manually and compare the batch names, statuses and request counts in the logs with the Batches page of the OpenAI platform.
  4. Enable hourly_check.

How to extend

  • Follow has_more and last_id with the after parameter when you create more than 100 batches in the window.
  • Filter on metadata (for example a job key you set at submission) to give each pipeline its own limits.
  • Download error_file_id with the Files API and attach the first failing lines to the Slack message.
  • Store the last status in a KV store and alert only when it changes.

Inputs

  • lookback_hours: type INT, default 48.
  • expiry_warning_hours: type INT, default 4.
  • warning_failed_request_pct: type FLOAT, default 2.0 (percent).
  • critical_failed_request_pct: type FLOAT, default 10.0 (percent).

Outputs

  • status: one of HEALTHY, WARNING, CRITICAL, LOW_VOLUME, UNREACHABLE.
  • Example path: {{ fromJson(outputs.summarize_batches.value).dead }} for the failed or expired batches.

Links

Pitfalls

  • Only the 100 most recent batches are read; page with after if you create more.
  • A cancelled batch is counted in the window but is not an alert, because it was canceled on purpose.
  • request_counts.failed covers requests that returned an error; a request that succeeded with an unhelpful answer is not a failure here.
  • Project API keys only see that project's batches; use one flow per project or a key with wider access.
  • This flow only reads; it never creates, cancels or resubmits a batch.
See How

New to Kestra?

Use blueprints to kickstart your first workflows.