Skip to content

Commit 7545306

Browse files
committed
docs: upadte docs fot the background jobs plugin
AdminForth/1857/add-queued-job-execution-to-th
1 parent 86cfbb1 commit 7545306

1 file changed

Lines changed: 76 additions & 0 deletions

File tree

adminforth/documentation/docs/tutorial/09-Plugins/23-background-jobs.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,11 +610,87 @@ async function loadTasks() {
610610

611611
```
612612
613+
## Queued jobs and concurrency limit
614+
615+
Running several long jobs at the same time can overload the server, so jobs are queued instead of being started unconditionally.
616+
617+
`startNewJob` counts the jobs of the same `jobHandlerName` which are already running. If the handler has a free concurrency slot the job starts immediately, exactly as before. If the limit is already reached the job and all its tasks are created in the `QUEUED` status, and the job is started automatically later, when a running job of the same handler finishes.
618+
619+
Each **jobHandlerName** has one FIFO queue, shared by all its jobs regardless of their job names. So
620+
`'Export users'` and `'Export orders'` of one handler do not run at the same time: the second one waits until the first finishes, and queued jobs are always started oldest first.
621+
622+
How many jobs of one handler may run at the same time is defined by `concurrencyLimit` of the handler.
623+
It defaults to `1`, so by default only one job per handler runs at a time:
624+
625+
```ts title="./index.ts"
626+
backgroundJobsPlugin.registerTaskHandler({
627+
jobHandlerName: 'example_job_handler',
628+
handler: async ({ jobId, setTaskStateField, getTaskStateField, getState }) => {
629+
...
630+
},
631+
// limit of tasks of one job that are running in parallel
632+
parallelLimit: 2,
633+
//diff-add
634+
// limit of jobs of this handler that are running at the same time, default is 1
635+
//diff-add
636+
concurrencyLimit: 1,
637+
})
638+
```
639+
640+
With `concurrencyLimit: 1` the first call below starts processing right away and the second one, made while
641+
the first job is still running, creates a `QUEUED` job which starts when the first one finishes:
642+
643+
```ts title="./index.ts"
644+
const jobId = await backgroundJobsPlugin.startNewJob(
645+
'Example Job', //job name
646+
req.adminUser, // adminuser
647+
[
648+
{ state: { task_number: 1, task_counter: 0 } },
649+
{ state: { task_number: 2, task_counter: 0 } },
650+
], //initial tasks
651+
'example_job_handler', //job handler name
652+
{ counter: 0 }, //initial job state
653+
)
654+
```
655+
656+
Use `queueNewJob` when a job must always go through the queue, even if a slot is free. It has the same signature as `startNewJob` and always creates the job in the `QUEUED` status.
657+
658+
When a job reaches a terminal status (`DONE`, `DONE_WITH_ERRORS` or `CANCELLED`) it frees its slot and the oldest queued job of the same handler is started automatically. The same happens after an application
659+
restart: jobs which were `IN_PROGRESS` are resumed first, and queued jobs are started only for handlers
660+
which still have a free slot.
661+
662+
If you want full control over when a queued job starts, create it with `autoStart: false` and start it yourself later:
663+
664+
```ts
665+
// job stays in QUEUED status, nothing is processed
666+
await backgroundJobsPlugin.queueNewJob(
667+
'Example Job', req.adminUser, tasks, 'example_job_handler', {}, { autoStart: false },
668+
)
669+
670+
// starts the oldest queued job of the handler if the concurrency limit allows it,
671+
// returns the started job id or null
672+
await backgroundJobsPlugin.startNextQueuedJob('example_job_handler')
673+
674+
// starts as many queued jobs of the handler as the concurrency limit allows
675+
await backgroundJobsPlugin.startQueuedJobs('example_job_handler')
676+
```
677+
678+
:::info
679+
A job never jumps the queue: `startNewJob` starts a job immediately only when the handler has a free slot
680+
**and** no other job is waiting in its queue. Otherwise the job is queued behind the ones created earlier.
681+
:::
682+
613683
## Backend API
614684
615685
The plugin provides some handy methods that can be used in different situations:
616686
617687
```ts
688+
//always create a job in QUEUED status, it is started by the queue of the handler when it has a free slot
689+
queueNewJob(jobName: string, adminUser: AdminUser, tasks: taskType[], jobHandlerName: string, initialState?: Record<string, any>, options?: { autoStart?: boolean })
690+
//start the oldest queued job of the handler if concurrencyLimit allows, returns started job id or null
691+
startNextQueuedJob(jobHandlerName: string)
692+
//start as many queued jobs of the handler as concurrencyLimit allows, returns started job ids
693+
startQueuedJobs(jobHandlerName: string)
618694
//set key:value to the job state in the DB
619695
setJobStateField(jobId: string, key: string, value: any)
620696
//get job field from the state in db

0 commit comments

Comments
 (0)