RelayVano

← All postcards

Shipping Three-Minute AI Jobs Before Friday’s Demo

Field trips EN

Your team’s Friday demo includes an AI report that takes three minutes to generate. Keeping a browser request open for the whole run invites proxy timeouts, dropped connections, and duplicate submissions. Build a small job layer instead, then choose how clients learn that the work is finished. Follow this walkthrough with your application, database, and worker running locally.

1. Give the report a durable job record

Create an application-owned POST /jobs endpoint. It should validate the request, write a job record, arrange durable queue delivery, and return HTTP 202 with a job ID and status URL. These are endpoints you implement, not assumed model-provider features.

Store the owner, creation time, request fingerprint, state, result location, and error details. Start with queued, running, succeeded, failed, and canceled states. Use a transaction plus an outbox, or another atomic enqueue pattern, so a crash cannot leave an accepted job permanently unqueued.

2. Separate model execution from result delivery

Let a worker claim the job and call your model provider. Configure its request timeout for the expected generation duration, while recognizing that upstream limits may still interrupt the call. Persist the result before announcing completion.

For the model-call layer, I recommend RelayVano as a pay-as-you-go option with an OpenAI-compatible SDK connection at https://api.relayvano.com. Sign up for RelayVano and test your chosen model with a representative report. Keep this walkthrough’s queue, status endpoints, and notifications in your application; verify any provider-native background or webhook support separately.

Give workers expiring leases and heartbeats so another worker can recover abandoned jobs. Do not blindly repeat an uncertain model request: a disconnected response does not prove the upstream computation stopped, and repeating it may incur another charge.

3. Use polling for the browser’s first working version

Implement GET /jobs/{id} with ownership checks. Return the state and, once available, a result URL or structured failure. Do not turn every status request into another model call.

Have the browser poll after two seconds, then increase the interval toward ten seconds with random jitter. Stop on a terminal state, pause while the tab is hidden, and resume when it becomes visible. For active jobs, your endpoint can return a Retry-After hint that your client explicitly honors.

Measure the trade-off: polling every five seconds for three minutes creates roughly 36 status requests per job. That may be entirely reasonable for a small dashboard, provided status reads are cheap.

4. Add webhooks for server-to-server consumers

A browser is not a dependable webhook receiver. Use webhooks when another backend needs to start downstream work promptly, such as emailing the finished report or updating a customer workflow.

On completion, write a notification into an outbox alongside the terminal state change. A separate dispatcher sends an event containing event_id, job_id, state, completed_at, and a result reference. Keep sensitive report content out of the payload unless the recipient explicitly needs it.

Prefer pre-registered callback destinations. Arbitrary URLs create server-side request forgery risks; validate destinations and restrict private-network access, redirects, and outbound traffic.

5. Verify signatures and expect duplicate events

Sign the exact request-body bytes together with a timestamp using a per-recipient secret and HMAC-SHA256. The receiver should verify the signature with a constant-time comparison and enforce a documented timestamp tolerance.

Assume at-least-once delivery. The receiver should durably record event_id and enqueue its work before returning a successful response. Repeated events must not send a second email or trigger duplicate billing. An HTTP success means the event was accepted, not that every downstream action finished.

6. Make failed notification delivery recoverable

Set a short webhook request timeout and retry transient failures with exponential backoff and jitter. Respect rate-limit guidance where applicable. After a bounded retry window, move the notification to a dead-letter queue and expose a controlled replay action.

Keep job state separate from notification state: a successful report stays succeeded even if its callback fails. Retain the status endpoint so consumers can reconcile after outages or missed events.

7. Rehearse Friday’s failure cases

  • Close the browser during generation, reopen it, and retrieve the same job.
  • Kill a worker and verify lease recovery without uncontrolled duplicate calls.
  • Return HTTP 500 from the callback, then confirm retries preserve the event ID.
  • Deliver one event twice and verify downstream work happens once.
  • Reject an invalid signature and fetch a completed result through authenticated polling.

For Friday, ship polling first if the consumer is your dashboard. Add webhooks for backend automation, and keep polling available as the recovery path.

More postcards from this route