background-joblisted
Install: claude install-skill rajurayhan/ai-agent-framework
# Background Job
## When to use
- Batch processing (payroll runs, PDF generation, exports)
- Scheduled reminders and accruals
- Any work exceeding request timeout
## Steps
1. Define event name in job client config
2. Handler validates + enqueues — never runs heavy computation in request
3. Implement handler with step boundaries per logical unit
4. **Idempotency**: key on entity ID; check status transactionally before work
5. Write audit logs for status transitions
6. Test: invoke twice, assert second is no-op
## Pattern
```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));
}
);
```
## Rules
- Every step safely re-runnable on retry
- Job drives status machine — don't leave entities half-updated
- Async mutations still write audit logs
## References
- `.cursor/rules/background-jobs.mdc`
- `.cursor/rules/testing.mdc` (idempotency: invoke twice, assert no-op)
- Claude equivalent: `background-jobs` skill
---
## Worked Example: Send Reminder Emails
Nightly job for pending requests older than 3 days.
**Idempotency:** `reminder_sent` flag checked inside each step.
```typescript
await step.run(