Skip to content

Batch API job finished

The Batch API (OpenAI, Anthropic) is cheaper than a regular call but runs asynchronously — from minutes to 24 hours. All that time the job hangs in in_progress, and refreshing the dashboard by hand is pointless. It’s far handier to get a push exactly when it becomes completed or failed, and with a “how many requests passed, how many failed” breakdown.

A small worker polls the status once a minute and sends an alert on transition to a terminal state:

import os, time, requests
import openai
NOTIFLY_URL = os.environ["NOTIFLY_URL"]
NOTIFLY_TOKEN = os.environ["NOTIFLY_TOKEN"]
POLL_SEC = 60
client = openai.OpenAI()
def notify(title, msg, prio):
requests.post(f"{NOTIFLY_URL}/message",
params={"token": NOTIFLY_TOKEN},
json={"title": title, "message": msg, "priority": prio},
timeout=5)
def watch_batch(batch_id):
"""Poll the job until it finishes; then push a summary."""
while True:
b = client.batches.retrieve(batch_id)
if b.status in ("completed", "failed", "expired", "cancelled"):
counts = b.request_counts # .completed / .failed / .total
if b.status == "completed" and counts.failed == 0:
notify(
f"✅ Batch готов: {counts.completed} запросов",
f"Джоба {batch_id} завершилась без ошибок.",
priority=5,
)
else:
notify(
f"⚠️ Batch {b.status}: {counts.failed} ошибок",
f"Готово {counts.completed}/{counts.total}, "
f"ошибок {counts.failed}. Проверьте error_file_id.",
priority=8,
)
return b.status
time.sleep(POLL_SEC)
# usage: submitted a batch and watching it
batch = client.batches.create(
input_file_id="file-abc", endpoint="/v1/chat/completions",
completion_window="24h")
watch_batch(batch.id)

Success with no errors is a quiet priority=5 (look at it when convenient); any failed or a failed/expired status is a loud priority=8, because part of the data came up short. request_counts saves you from downloading the result just to gauge the scale.

Option 2: don’t hold a process — cron/YC function

Section titled “Option 2: don’t hold a process — cron/YC function”

If you don’t want to keep a worker alive for a day, move the polling into a scheduled function on Yandex Cloud with a timer-trigger. Keep the list of active batch_ids in a file/YDB, check statuses on each tick, and cross off the finished ones. A ready skeleton is in the recipe Custom cloud function for integrity checks: the same handler, only instead of /health it calls client.batches.retrieve.

Option 3: provider webhook → Webhook Router

Section titled “Option 3: provider webhook → Webhook Router”

If the provider can send a webhook on batch completion (OpenAI supports this), you don’t need polling at all. Point the webhook at the Webhook Router — it will turn the batch.completed event into a push instantly, without a single status poll.

  • the batch_id and final status (completed / failed / expired);
  • the completed / failed / total breakdown;
  • the error_file_id if there were errors — to go straight for details;
  • how long the job ran (useful for planning the next one).