vault backup: 2026-05-15 15:56:59

This commit is contained in:
Vadym Samoilenko 2026-05-15 15:56:59 +01:00
parent 08ef13e44f
commit bf90c5c48e
4 changed files with 203 additions and 1 deletions

View file

@ -35,7 +35,7 @@ This 3-hop pattern works for hundreds of articles without vector search.
| [[wiki/reports/_index\|reports/]] | Weekly and monthly summaries — generate: `uv run python scripts/report-generator.py --weekly` | 1 |
| [[wiki/infrastructure/_index\|infrastructure/]] | Server inventory: all 10 SSH hosts — optical, optical-dev, optical-prod, baic, librechat, modocmms, box-cli, aimpress, pve | 12 |
| [[wiki/testing/_index\|testing/]] | Web app testing: functional, performance, security, UI types; TDD/BDD/Agile methodologies; Selenium/Cypress/Playwright/JMeter/OWASP ZAP tools | 1 |
| [[wiki/payloadcms/_index\|payloadcms/]] | Full Payload CMS reference — getting started, config, database (Postgres/MongoDB/SQLite), all 22 field types, access control, hooks, authentication (cookies, JWT, API keys, custom strategies, token data), admin UI, custom components, Lexical rich text, live preview, versions/drafts, Local/REST/GraphQL APIs, queries, plugins, jobs queue, upload, ecommerce, production deploy, TypeScript, migration guides, i18n, localization, hierarchy | 96 |
| [[wiki/payloadcms/_index\|payloadcms/]] | Full Payload CMS reference — getting started, config, database (Postgres/MongoDB/SQLite), all 22 field types, access control, hooks, authentication (cookies, JWT, API keys, custom strategies, token data), admin UI, custom components, Lexical rich text, live preview, versions/drafts, Local/REST/GraphQL APIs, queries, plugins, jobs queue, upload, ecommerce, production deploy, TypeScript, migration guides, i18n, localization, hierarchy | 97 |
| [[wiki/shared-patterns/_index\|shared-patterns/]] | Oliver Agency standard library patterns: httpx, structlog, pydantic-settings, alembic — reuse before writing from scratch | 4 |
| [[wiki/mistakes/_index\|mistakes/]] | Anti-patterns extracted from sessions — per-stack running lists (fastapi, react, docker, postgres, general) — injected at session start | 5 |

View file

@ -8,6 +8,7 @@
| [[wiki/payloadcms/admin-preferences\|Admin Preferences]] | Per-user persistent preferences via `usePreferences` hook — built-ins, DB schema, REST/GraphQL, usage pattern | raw/admin__preferences.md | 2026-05-15 |
| [[wiki/payloadcms/admin-preview\|Admin Preview & Draft Preview]] | Preview button config, draft preview flow with Next.js (3 steps), conditional preview, PREVIEW_SECRET guard | raw/admin__preview.md | 2026-05-15 |
| [[wiki/payloadcms/jobs-queue\|Jobs Queue]] | Full reference: Tasks, Jobs, Queues, Workflows, Schedules, concurrency controls, worker strategies, gotchas | raw/jobs-queue__*.md | 2026-05-15 |
| [[wiki/payloadcms/jobs-queue-jobs\|Jobs Queue — Jobs Detail]] | Queuing from hooks/endpoints/server actions, job options (waitUntil/queue/log), full status schema, access control (jobs.access + overrideAccess), cancellation (cancelByID/cancel/JobCancelledError) | raw/jobs-queue__jobs.md | 2026-05-15 |
| [[wiki/payloadcms/admin\|Admin Panel (full)]] | Complete admin config reference: preview, draft-preview, preferences API, all React hooks | raw/admin__*.md | 2026-05-15 |
| [[wiki/payloadcms/custom-components\|Custom Components]] | Root slots, dashboard widgets, edit/list view slots, document views, custom views, providers | raw/custom-components__*.md | 2026-05-15 |

View file

@ -0,0 +1,201 @@
---
title: "Jobs Queue — Jobs: Queuing, Status, Access Control, Cancellation"
aliases: [payload-jobs-detail, jobs-queue-detail]
tags: [payloadcms, jobs-queue, typescript]
sources: [raw/jobs-queue__jobs.md]
created: 2026-05-15
updated: 2026-05-15
---
# Jobs Queue — Jobs (Detail)
A **Job** is a runtime instance of a Task or Workflow stored in `payload-jobs`.
See the full overview at [[wiki/payloadcms/jobs-queue|Jobs Queue Overview]].
---
## Queuing a Job
```ts
// Queue a Workflow
await payload.jobs.queue({
workflow: 'createPostAndUpdate',
input: { title: 'my title' },
})
// Queue a single Task
await payload.jobs.queue({
task: 'createPost',
input: { title: 'my title' },
})
```
### Where to Queue
| Location | Pattern |
|----------|---------|
| Collection `afterChange` hook | `req.payload.jobs.queue(...)` — most common |
| Field `afterChange` hook | Trigger on specific field change (e.g. image variants on upload change) |
| Custom REST endpoint | `req.payload.jobs.queue(...)`, return `job.id` to caller |
| Next.js Server Action | `getPayload({ config })``payload.jobs.queue(...)` |
#### Collection hook example
```ts
afterChange: [async ({ req, doc, operation }) => {
if (operation === 'update' && doc.status === 'published') {
await req.payload.jobs.queue({
task: 'notifySubscribers',
input: { postId: doc.id },
})
}
}]
```
#### Server Action example
```ts
'use server'
import { getPayload } from 'payload'
import config from '@payload-config'
export async function scheduleEmail(userId: string) {
const payload = await getPayload({ config })
await payload.jobs.queue({ task: 'sendEmail', input: { userId } })
}
```
---
## Job Options
```ts
await payload.jobs.queue({
task: 'sendEmail',
input: { userId: '123' },
waitUntil: new Date('2024-12-25T00:00:00Z'), // schedule for future
queue: 'high-priority', // assign to named queue
log: [{ message: 'Queued by admin', createdAt: new Date().toISOString() }],
req, // pass request context for access control
})
```
| Option | Description |
|--------|-------------|
| `waitUntil` | Run at specific future date/time |
| `queue` | Named queue (default: `'default'`) |
| `log` | Custom log entries for debugging/tracking |
| `req` | Request context (required for access control) |
---
## Job Status
### Check after queuing
```ts
const job = await payload.jobs.queue({ task: 'processPayment', input: { orderId: '123' } })
const updatedJob = await payload.findByID({
collection: 'payload-jobs',
id: job.id,
})
updatedJob.completedAt // ISO string when finished (null if pending)
updatedJob.hasError // true if failed
updatedJob.taskStatus // per-task details (for workflows)
```
### Full job document schema
```ts
{
id: 'job_123',
taskSlug: 'sendEmail', // or workflowSlug for workflows
input: { userId: '123' },
completedAt: '2024-01-15...', // null if still pending
hasError: false,
totalTried: 1, // number of execution attempts
processing: false, // true if currently running
taskStatus: { // per-task (workflows only)
sendEmail: {
'1': { complete: true, output: { emailSent: true } }
}
},
log: [{ message: 'Job started', createdAt: '...' }],
}
```
---
## Access Control
By default, `payload.jobs.*` Local API calls **bypass** access control.
### Define access rules in Jobs Config
```ts
jobs: {
access: {
queue: ({ req }) => req.user?.roles?.includes('admin'),
run: ({ req }) => req.user?.roles?.includes('admin'),
cancel: ({ req }) => req.user?.roles?.includes('admin'),
},
}
```
- Each function receives `req` and returns `boolean`
- If undefined, authenticated users can perform the operation
- **Do NOT** set access control on the `payload-jobs` collection directly — may be deprecated
### Enable access control in Local API
```ts
const req = await createLocalReq({ user }, payload)
await payload.jobs.queue({
workflow: 'createPost',
input: { title: 'My Post' },
overrideAccess: false, // enforce access control
req, // must include user context
})
```
---
## Cancelling Jobs
```ts
// Cancel single job
await payload.jobs.cancelByID({ id: createdJob.id })
// Cancel multiple jobs by query
await payload.jobs.cancel({
where: { workflowSlug: { equals: 'createPost' } },
})
```
- Cancelling a **running** job: current task finishes, subsequent tasks are skipped
- Cancellation is checked **between tasks**, not mid-task
- From inside a handler: `throw new JobCancelledError('reason')`
---
## Key Takeaways
- Jobs are instances of Tasks or Workflows stored in `payload-jobs`
- Queue from anywhere: collection hooks (most common), field hooks, endpoints, server actions
- `waitUntil` for one-time future scheduling; `queue` to segment execution pools
- Full job status is in `payload-jobs` collection — `completedAt`, `hasError`, `taskStatus`
- Access control lives in `jobs.access` config, **not** on the collection; use `overrideAccess: false` + `req` to enforce
- Cancellation is inter-task (current task finishes); use `JobCancelledError` from within handlers
---
## Related
- [[wiki/payloadcms/jobs-queue|Jobs Queue — Full Reference]] (tasks, workflows, queues, schedules, gotchas)
- [[wiki/payloadcms/hooks-collections|Collection Hooks]] (most common place to queue jobs)
- [[wiki/payloadcms/authentication-overview|Authentication Overview]] (access control patterns)
- [[wiki/payloadcms/local-api|Local API]] (`payload.jobs.*`, `overrideAccess`)