Skip to navigation

Asynchronous jobs

How work that takes too long for one request is queued and collected.
View as Markdown

Four features take longer than a single HTTP request should: image filters and overlays, website screenshots, and Minecraft renders. Rather than hold the connection open, Aegis queues the work and answers immediately with a jobId you collect the result from.

const shot = await aegis.tools.screenshot({ url: 'https://aegi.run' })
// { jobId: '3f8a...', status: 'pending', url: 'https://aegi.run' }
const { result } = await aegis.jobs.wait(shot.jobId, { timeout: 60 })

Job types

FeatureJob type
Image filter and overlayfilters, overlays
Website screenshotscreenshot
Minecraft rendermcrender

The job object

Both endpoints answer with the same record:

{
"data": {
"id": "3f8a1c8e-5b7d-2049-af31-c6e8d5b90742",
"type": "screenshot",
"status": "completed",
"result": { "url": "https://files.aegi.run/9c1e..." },
"createdAt": 1770643920000,
"updatedAt": 1770643934000
}
}

status moves through:

StatusMeaning
pendingQueued, not started yet
processingA worker has picked it up
completedFinished; read result
failedStopped; read error

result is typed unknown in the spec on purpose — its shape is decided by the render worker rather than the API, so it differs per job type and is not pinned to a schema. Read it defensively. payload is the original job parameters, echoed back for traceability.

Music never uses jobs. A player is long-lived state you drive directly, not work that finishes — see Music.

Waiting instead of polling

GET /v1/jobs/{id}/wait holds the request open until the job reaches a final state, so you spend one request instead of a polling loop.

const job = await aegis.jobs.wait(jobId, { timeout: 60 })

timeout is in seconds, between 1 and 300, and defaults to 30.

A wait that times out returns 504 with the job still attached — the same body as a success, just a different status. Check the status code, or catch the AegisError the SDK raises for it, and the job may well have finished moments later.

Polling directly

GET /v1/jobs/{id} is a plain read and never blocks. Poll it at a sensible interval rather than in a tight loop:

let job = await aegis.jobs.get(jobId)
while (job.status === 'pending' || job.status === 'processing') {
await new Promise((r) => setTimeout(r, 1000))
job = await aegis.jobs.get(jobId)
}
if (job.status === 'failed') throw new Error(job.error)

Polling costs you a cheap class request each time, which is metered — see rate limits. Prefer wait when you can.

Expiry

Job records are kept for 24 hours. After that, both endpoints answer 404 with "Job not found", and a jobId is no longer collectable.

The rendered image itself is a separate artefact and outlives the job record. Copy the result URL when the job completes if you need it later.