background-jobslisted
Install: claude install-skill rajurayhan/ai-agent-framework
# Background Jobs
Batch processing, PDF generation, and reminders must run as background jobs — they can exceed function time limits and request-scoped failure shouldn't leave entities half-processed.
## Pattern
1. Server handler validates input and permissions (see `add-server-action`), then **enqueues** an event — it does not perform heavy computation itself.
2. Job handler does the work, broken into `step.run(...)` steps so partial progress survives retries.
3. **Idempotency is mandatory**: key on entity ID; check/set status transactionally before work — retried/duplicate events must be safe no-ops.
4. Job drives status machine and writes audit logs — async doesn't exempt auditing.
## Rules
- Never perform batch computation, PDF rendering, or bulk export inside a request handler directly
- Every job that mutates money data writes audit log entries
- Design every step to be safely re-runnable on retry
## Example
```typescript
createFunction(
{ id: 'process-entity', idempotency: 'event.data.entityId' },
{ event: 'entity/process.requested' },
async ({ event, step }) => {
const entity = await step.run('load', () => loadEntity(event.data.entityId));
if (entity.status === 'processed') return { skipped: true };
await step.run('process', () => processEntity(entity));
await step.run('mark-done', () => markProcessed(entity));
}
);
```
Test: invoke twice, assert second is no-op. See `testing-conventions` for job testing.
Full worked example: If Cursor