From 8135ac3358e45b4af804f5ab6da022fe625aed49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:47:21 -0300 Subject: [PATCH 1/4] set up cron jobs on init in payload-cloud --- packages/payload-cloud/package.json | 1 + packages/payload-cloud/src/plugin.ts | 58 +++++++++++++++++++++++++++- packages/payload-cloud/src/types.ts | 35 +++++++++++++++++ pnpm-lock.yaml | 58 ++++++++-------------------- 4 files changed, 109 insertions(+), 43 deletions(-) diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index 4a35680edc0..160e9999398 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -57,6 +57,7 @@ "ts-jest": "^29.1.0" }, "peerDependencies": { + "croner": "9.0.0", "payload": "workspace:*" }, "publishConfig": { diff --git a/packages/payload-cloud/src/plugin.ts b/packages/payload-cloud/src/plugin.ts index f0d0e56d3f0..b77567a4082 100644 --- a/packages/payload-cloud/src/plugin.ts +++ b/packages/payload-cloud/src/plugin.ts @@ -1,5 +1,7 @@ import type { Config } from 'payload' +import { Cron } from 'croner' + import type { PluginOptions } from './types.js' import { payloadCloudEmail } from './email.js' @@ -93,5 +95,59 @@ export const payloadCloudPlugin = }) } - return config + // If the user has tasks configured, we set up cron jobs on init. + // We also make sure to only run on one instance using a instance identifier stored in a global. + if (config.jobs?.tasks) { + config.globals = [ + ...(config.globals || []), + { + slug: 'payload-cloud-instance', + admin: { + hidden: true, + }, + fields: [ + { + name: 'instance', + type: 'text', + required: true, + }, + ], + }, + ] + config.onInit = async (payload) => { + if (config.onInit) { + await config.onInit(payload) + } + const instance = generateRandomString() + + await payload.updateGlobal({ + slug: 'payload-cloud-instance', + data: { + instance, + }, + }) + + const cloudInstance = await payload.findGlobal({ + slug: 'payload-cloud-instance', + }) + + if (cloudInstance.instance === instance) { + pluginOptions?.jobs?.forEach((cronConfig) => { + new Cron(cronConfig.cron ?? '* * * * *', async () => { + await payload.jobs.run({ + limit: cronConfig.limit ?? 100, + queue: cronConfig.queue, + }) + }) + }) + } + } + + return config + } } + +function generateRandomString(): string { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + return Array.from({ length: 24 }, () => chars[Math.floor(Math.random() * chars.length)]).join('') +} diff --git a/packages/payload-cloud/src/types.ts b/packages/payload-cloud/src/types.ts index 642440fbdce..613983f2e69 100644 --- a/packages/payload-cloud/src/types.ts +++ b/packages/payload-cloud/src/types.ts @@ -53,6 +53,36 @@ export interface PayloadCloudEmailOptions { skipVerify?: boolean } +export type CronConfig = { + /** + * The cron schedule for the job. Defaults to '* * * * *' (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) + * │ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat + * │ │ │ │ │ + * │ │ │ │ │ + * - '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 100. + */ + limit?: number + /** + * The queue name for the job. + */ + queue?: string +} + export interface PluginOptions { /** Payload Cloud Email * @default true @@ -72,6 +102,11 @@ export interface PluginOptions { */ endpoint?: string + /** + * Jobs configuration + */ + jobs?: CronConfig[] + /** Payload Cloud Storage * @default true */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1459dad9c1d..5076edfe168 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: 1.48.1 '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.3(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13))) '@sentry/node': specifier: ^8.33.1 version: 8.37.1 @@ -147,7 +147,7 @@ importers: version: 9.5.0(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0))) next: specifier: 15.0.3 - version: 15.0.3(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-df7b47d-20241124)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-df7b47d-20241124)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) open: specifier: ^10.1.0 version: 10.1.0 @@ -946,6 +946,9 @@ importers: amazon-cognito-identity-js: specifier: ^6.1.2 version: 6.3.12 + croner: + specifier: 9.0.0 + version: 9.0.0 nodemailer: specifier: 6.9.10 version: 6.9.10 @@ -1087,7 +1090,7 @@ importers: dependencies: '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.4(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.4(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13))) '@sentry/types': specifier: ^8.33.1 version: 8.37.1 @@ -1434,7 +1437,7 @@ importers: version: link:../plugin-cloud-storage uploadthing: specifier: 7.3.0 - version: 7.3.0(next@15.0.4(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) + version: 7.3.0(next@15.0.4(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) devDependencies: payload: specifier: workspace:* @@ -1708,7 +1711,7 @@ importers: version: link:../packages/ui '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.3(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13))) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13))) '@sentry/react': specifier: ^7.77.0 version: 7.119.2(react@19.0.0) @@ -1753,7 +1756,7 @@ importers: version: 8.8.3(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.0.3 - version: 15.0.3(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-df7b47d-20241124)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + version: 15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-df7b47d-20241124)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) nodemailer: specifier: 6.9.10 version: 6.9.10 @@ -13662,7 +13665,7 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.3(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13)))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13)))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -13678,7 +13681,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13))) chalk: 3.0.0 - next: 15.0.3(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-df7b47d-20241124)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-df7b47d-20241124)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -13691,7 +13694,7 @@ snapshots: - supports-color - webpack - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.4(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13)))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.0.4(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13)))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -13707,7 +13710,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.13))) chalk: 3.0.0 - next: 15.0.4(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.0.4(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -18423,36 +18426,7 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.0.3(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.0.0-beta-df7b47d-20241124)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): - dependencies: - '@next/env': 15.0.3 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.13 - busboy: 1.6.0 - caniuse-lite: 1.0.30001678 - postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(@babel/core@7.26.0)(babel-plugin-macros@3.1.0)(react@19.0.0) - optionalDependencies: - '@next/swc-darwin-arm64': 15.0.3 - '@next/swc-darwin-x64': 15.0.3 - '@next/swc-linux-arm64-gnu': 15.0.3 - '@next/swc-linux-arm64-musl': 15.0.3 - '@next/swc-linux-x64-gnu': 15.0.3 - '@next/swc-linux-x64-musl': 15.0.3 - '@next/swc-win32-arm64-msvc': 15.0.3 - '@next/swc-win32-x64-msvc': 15.0.3 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.48.1 - babel-plugin-react-compiler: 19.0.0-beta-df7b47d-20241124 - sass: 1.77.4 - sharp: 0.33.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - next@15.0.4(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): + next@15.0.4(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): dependencies: '@next/env': 15.0.4 '@swc/counter': 0.1.3 @@ -20187,14 +20161,14 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - uploadthing@7.3.0(next@15.0.4(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): + uploadthing@7.3.0(next@15.0.4(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): dependencies: '@effect/platform': 0.69.8(effect@3.10.3) '@uploadthing/mime-types': 0.3.2 '@uploadthing/shared': 7.1.1 effect: 3.10.3 optionalDependencies: - next: 15.0.4(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.0.4(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.48.1)(babel-plugin-macros@3.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) uri-js@4.4.1: dependencies: From 6deaa1f6161155561e40524b936fa49914da5c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:59:34 -0300 Subject: [PATCH 2/4] fix comments --- packages/payload-cloud/src/plugin.ts | 92 +++++++++++++++------------- packages/payload-cloud/src/types.ts | 27 ++++++-- 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/packages/payload-cloud/src/plugin.ts b/packages/payload-cloud/src/plugin.ts index b77567a4082..d38cf4741b4 100644 --- a/packages/payload-cloud/src/plugin.ts +++ b/packages/payload-cloud/src/plugin.ts @@ -95,56 +95,66 @@ export const payloadCloudPlugin = }) } - // If the user has tasks configured, we set up cron jobs on init. + // We set up cron jobs on init. // We also make sure to only run on one instance using a instance identifier stored in a global. - if (config.jobs?.tasks) { - config.globals = [ - ...(config.globals || []), - { - slug: 'payload-cloud-instance', - admin: { - hidden: true, - }, - fields: [ - { - name: 'instance', - type: 'text', - required: true, - }, - ], + + // If you modify this defaults, make sure to update the TsDoc in the types file. + const DEFAULT_CRON = '* * * * *' + const DEFAULT_LIMIT = 10 + const DEFAULT_CRON_JOB = { + cron: DEFAULT_CRON, + limit: DEFAULT_LIMIT, + queue: 'default (every minute)', + } + config.globals = [ + ...(config.globals || []), + { + slug: 'payload-cloud-instance', + admin: { + hidden: true, }, - ] - config.onInit = async (payload) => { - if (config.onInit) { - await config.onInit(payload) - } - const instance = generateRandomString() - - await payload.updateGlobal({ - slug: 'payload-cloud-instance', - data: { - instance, + fields: [ + { + name: 'instance', + type: 'text', + required: true, }, - }) + ], + }, + ] + const newOnInit = async (payload) => { + if (config.onInit) { + await config.onInit(payload) + } + const instance = generateRandomString() - const cloudInstance = await payload.findGlobal({ - slug: 'payload-cloud-instance', - }) + await payload.updateGlobal({ + slug: 'payload-cloud-instance', + data: { + instance, + }, + }) - if (cloudInstance.instance === instance) { - pluginOptions?.jobs?.forEach((cronConfig) => { - new Cron(cronConfig.cron ?? '* * * * *', async () => { - await payload.jobs.run({ - limit: cronConfig.limit ?? 100, - queue: cronConfig.queue, - }) + const cloudInstance = await payload.findGlobal({ + slug: 'payload-cloud-instance', + }) + + const cronJobs = pluginOptions?.cronJobs?.run ?? [DEFAULT_CRON_JOB] + if (cloudInstance.instance === instance) { + cronJobs.forEach((cronConfig) => { + new Cron(cronConfig.cron ?? DEFAULT_CRON, async () => { + await payload.jobs.run({ + limit: cronConfig.limit ?? DEFAULT_LIMIT, + queue: cronConfig.queue, }) }) - } + }) } - - return config } + + config.onInit = newOnInit + + return config } function generateRandomString(): string { diff --git a/packages/payload-cloud/src/types.ts b/packages/payload-cloud/src/types.ts index 613983f2e69..ca57a8222ed 100644 --- a/packages/payload-cloud/src/types.ts +++ b/packages/payload-cloud/src/types.ts @@ -74,7 +74,7 @@ export type CronConfig = { */ cron?: string /** - * The limit for the job. This can be overridden by the user. Defaults to 100. + * The limit for the job. This can be overridden by the user. Defaults to 10. */ limit?: number /** @@ -84,6 +84,26 @@ export type CronConfig = { } export interface PluginOptions { + /** + * Jobs configuration. By default, there is a single + * cron job that runs every minute. + */ + cronJobs?: { + /** + * Enable the cron jobs defined in the `run` array, + * or the default cron job if `run` is not defined. + * Defaults to `true`. + * @note If you change this in a development environment, + * you will need to restart the server for the changes to take effect. + */ + enabled?: boolean + /** + * Cron jobs configuration. If not defined, a single + * cron job is created that runs every minute. + */ + run?: CronConfig[] + } + /** Payload Cloud Email * @default true */ @@ -102,11 +122,6 @@ export interface PluginOptions { */ endpoint?: string - /** - * Jobs configuration - */ - jobs?: CronConfig[] - /** Payload Cloud Storage * @default true */ From 3f374993db397f3592de532959d84746ceb26157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:50:42 -0300 Subject: [PATCH 3/4] add test, fix comments --- packages/payload-cloud/src/plugin.spec.ts | 32 +++++++++++++++++++++++ packages/payload-cloud/src/types.ts | 30 ++++++++++----------- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/packages/payload-cloud/src/plugin.spec.ts b/packages/payload-cloud/src/plugin.spec.ts index 3deeddad772..003b2804d77 100644 --- a/packages/payload-cloud/src/plugin.spec.ts +++ b/packages/payload-cloud/src/plugin.spec.ts @@ -165,6 +165,38 @@ describe('plugin', () => { }) }) }) + + describe('cron jobs', () => { + test('should always set global instance identifier, even with no cron jobs or enabled: false', async () => { + const plugin = payloadCloudPlugin({ + cronJobs: { + enabled: false, + }, + }) + const config = await plugin(createConfig()) + + const globalInstance = config.globals?.find( + (global) => global.slug === 'payload-cloud-instance', + ) + + expect(globalInstance).toBeDefined() + expect(globalInstance?.fields).toStrictEqual([ + { + name: 'instance', + type: 'text', + required: true, + }, + ]), + expect(globalInstance?.admin?.hidden).toStrictEqual(true) + + const plugin2 = payloadCloudPlugin() + const config2 = await plugin(createConfig()) + const globalInstance2 = config2.globals?.find( + (global) => global.slug === 'payload-cloud-instance', + ) + expect(globalInstance2).toBeDefined() + }) + }) }) function assertCloudStorage(config: Config) { diff --git a/packages/payload-cloud/src/types.ts b/packages/payload-cloud/src/types.ts index ca57a8222ed..f1595ebf935 100644 --- a/packages/payload-cloud/src/types.ts +++ b/packages/payload-cloud/src/types.ts @@ -55,22 +55,22 @@ export interface PayloadCloudEmailOptions { export type CronConfig = { /** - * The cron schedule for the job. Defaults to '* * * * *' (every minute). + * 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) - * │ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat - * │ │ │ │ │ - * │ │ │ │ │ - * - '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 + * ┌───────────── 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 /** @@ -92,7 +92,7 @@ export interface PluginOptions { /** * Enable the cron jobs defined in the `run` array, * or the default cron job if `run` is not defined. - * Defaults to `true`. + * @default true * @note If you change this in a development environment, * you will need to restart the server for the changes to take effect. */ From bee3a42dc975e4a65edd2bd372de93ed88d14a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Sun, 22 Dec 2024 10:29:30 -0300 Subject: [PATCH 4/4] waitRandomTime --- packages/payload-cloud/src/plugin.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/payload-cloud/src/plugin.ts b/packages/payload-cloud/src/plugin.ts index d38cf4741b4..9c1914ab5f0 100644 --- a/packages/payload-cloud/src/plugin.ts +++ b/packages/payload-cloud/src/plugin.ts @@ -135,6 +135,8 @@ export const payloadCloudPlugin = }, }) + await waitRandomTime() + const cloudInstance = await payload.findGlobal({ slug: 'payload-cloud-instance', }) @@ -157,6 +159,14 @@ export const payloadCloudPlugin = return config } +function waitRandomTime(): Promise { + const min = 1000 // 1 second in milliseconds + const max = 5000 // 5 seconds in milliseconds + const randomTime = Math.floor(Math.random() * (max - min + 1)) + min + + return new Promise((resolve) => setTimeout(resolve, randomTime)) +} + function generateRandomString(): string { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' return Array.from({ length: 24 }, () => chars[Math.floor(Math.random() * chars.length)]).join('')