From c0dc0cca374c1fa64115b305ffee01a285edab89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:51:26 -0300 Subject: [PATCH] feat: autoRun jobs (#10401) This pull request introduces the ability to configure cron jobs for automatically running tasks in the job queue. --- docs/jobs-queue/queues.mdx | 28 ++++++++++++- packages/payload/src/index.ts | 21 ++++++++++ .../payload/src/queues/config/types/index.ts | 40 +++++++++++++++++-- 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/docs/jobs-queue/queues.mdx b/docs/jobs-queue/queues.mdx index ee5b7d6dd..4e002b8bd 100644 --- a/docs/jobs-queue/queues.mdx +++ b/docs/jobs-queue/queues.mdx @@ -25,7 +25,33 @@ Then, you could configure two different runner strategies: ## Executing jobs -As mentioned above, you can queue jobs, but the jobs won't run unless a worker picks up your jobs and runs them. This can be done in two ways: +As mentioned above, you can queue jobs, but the jobs won't run unless a worker picks up your jobs and runs them. This can be done in four ways: + +#### Cron jobs + +You can use the jobs.autoRun property to configure cron jobs: + +```ts +export default buildConfig({ + // Other configurations... + jobs: { + tasks: [ + // your tasks here + ], + // autoRun can optionally be a function that receives payload as an argument + autoRun: [ + { + cron: '0 * * * *', // every hour at minute 0 + limit: 100, // limit jobs to process each run + queue: 'hourly', // name of the queue + }, + // add as many cron jobs as you want + ], + }, +}) +``` + +autoRun is intended for use with a dedicated server that is always running, and should not be used on serverless platforms like Vercel. #### Endpoint diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index 599c06068..4ccf6e912 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -63,6 +63,8 @@ import type { } from './types/index.js' import type { TraverseFieldsCallback } from './utilities/traverseFields.js' export type { FieldState } from './admin/forms/Form.js' +import { Cron } from 'croner' + import type { TypeWithVersion } from './versions/types.js' import { decrypt, encrypt } from './auth/crypto.js' @@ -712,6 +714,25 @@ export class BasePayload { await this.config.onInit(this) } } + if (this.config.jobs.autoRun) { + const DEFAULT_CRON = '* * * * *' + const DEFAULT_LIMIT = 10 + + const cronJobs = + typeof this.config.jobs.autoRun === 'function' + ? await this.config.jobs.autoRun(this) + : this.config.jobs.autoRun + await Promise.all( + cronJobs.map((cronConfig) => { + new Cron(cronConfig.cron ?? DEFAULT_CRON, async () => { + await this.jobs.run({ + limit: cronConfig.limit ?? DEFAULT_LIMIT, + queue: cronConfig.queue, + }) + }) + }), + ) + } return this } diff --git a/packages/payload/src/queues/config/types/index.ts b/packages/payload/src/queues/config/types/index.ts index 45d39025f..fec620d9a 100644 --- a/packages/payload/src/queues/config/types/index.ts +++ b/packages/payload/src/queues/config/types/index.ts @@ -1,8 +1,38 @@ import type { CollectionConfig } from '../../../index.js' -import type { PayloadRequest } from '../../../types/index.js' +import type { Payload, PayloadRequest } from '../../../types/index.js' import type { TaskConfig } from './taskTypes.js' import type { WorkflowConfig } from './workflowTypes.js' +export type CronConfig = { + /** + * The cron schedule for the job. + * @default '* * * * *' (every minute). + * + * @example + * ┌───────────── minute (0 - 59) + * │ ┌───────────── hour (0 - 23) + * │ │ ┌───────────── day of the month (1 - 31) + * │ │ │ ┌───────────── month (1 - 12) + * │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday) + * │ │ │ │ │ + * │ │ │ │ │ + * - '0 * * * *' every hour at minute 0 + * - '0 0 * * *' daily at midnight + * - '0 0 * * 0' weekly at midnight on Sundays + * - '0 0 1 * *' monthly at midnight on the 1st day of the month + * - '0/5 * * * *' every 5 minutes + */ + cron?: string + /** + * The limit for the job. This can be overridden by the user. Defaults to 10. + */ + limit?: number + /** + * The queue name for the job. + */ + queue?: string +} + export type RunJobAccessArgs = { req: PayloadRequest } @@ -19,14 +49,18 @@ export type JobsConfig = { */ run?: RunJobAccess } - /** - * Adds information about the parent job to the task log. This is useful for debugging and tracking the flow of tasks. + /** Adds information about the parent job to the task log. This is useful for debugging and tracking the flow of tasks. * * In 4.0, this will default to `true`. * * @default false */ addParentToTaskLog?: boolean + /** + * Queue cron jobs automatically on payload initialization. + * @remark this property should not be used on serverless platforms like Vercel + */ + autoRun?: ((payload: Payload) => CronConfig[] | Promise) | CronConfig[] /** * Determine whether or not to delete a job after it has successfully completed. */