fix(plugin-cloud): ensure scheduled publishing works if no custom jobs are defined (#12410)

Previously, plugin-cloud would only set up job auto-running if a job configuration was present in the custom config at initialization time.

However, some jobs - such as the scheduled publish job which is added during sanitization - are added after plugin-cloud has initialized. This means relying solely on the initial state of the job config is insufficient for determining whether to enable auto-running.

This PR removes that check and ensures auto-running is always initialized, allowing later-added jobs to run as expected.

## Weakening type

This PR also weakens to `config.jobs.tasks` type and makes that property optional. It's totally permissible to only have workflows that define inline tasks, and to not have any static tasks defined in `config.jobs.tasks`. Thus it makes no sense to make that property required.
This commit is contained in:
Alessio Gravili
2025-05-14 14:58:25 -07:00
committed by GitHub
parent 93d79b9c62
commit d63c8baea5
7 changed files with 22 additions and 25 deletions

View File

@@ -16,6 +16,14 @@ export const generateRandomString = (): string => {
return Array.from({ length: 24 }, () => chars[Math.floor(Math.random() * chars.length)]).join('')
}
const DEFAULT_CRON = '* * * * *'
const DEFAULT_LIMIT = 10
const DEFAULT_CRON_JOB = {
cron: DEFAULT_CRON,
limit: DEFAULT_LIMIT,
queue: 'default',
}
export const payloadCloudPlugin =
(pluginOptions?: PluginOptions) =>
async (incomingConfig: Config): Promise<Config> => {
@@ -100,15 +108,6 @@ export const payloadCloudPlugin =
}
// We make sure to only run cronjobs on one instance using a instance identifier stored in a global.
const DEFAULT_CRON = '* * * * *'
const DEFAULT_LIMIT = 10
const DEFAULT_CRON_JOB = {
cron: DEFAULT_CRON,
limit: DEFAULT_LIMIT,
queue: 'default',
}
config.globals = [
...(config.globals || []),
{
@@ -126,13 +125,13 @@ export const payloadCloudPlugin =
},
]
if (pluginOptions?.enableAutoRun === false || !config.jobs) {
if (pluginOptions?.enableAutoRun === false) {
return config
}
const oldAutoRunCopy = config.jobs.autoRun ?? []
const oldAutoRunCopy = config.jobs?.autoRun ?? []
const hasExistingAutorun = Boolean(config.jobs.autoRun)
const hasExistingAutorun = Boolean(config.jobs?.autoRun)
const newShouldAutoRun = async (payload: Payload) => {
if (process.env.PAYLOAD_CLOUD_JOBS_INSTANCE) {
@@ -150,8 +149,8 @@ export const payloadCloudPlugin =
return false
}
if (!config.jobs.shouldAutoRun) {
config.jobs.shouldAutoRun = newShouldAutoRun
if (!config.jobs?.shouldAutoRun) {
;(config.jobs ??= {}).shouldAutoRun = newShouldAutoRun
}
const newAutoRun = async (payload: Payload) => {

View File

@@ -88,7 +88,7 @@ export function generateJobsJSONSchemas(
additionalProperties: false,
properties: {
...Object.fromEntries(
jobsConfig.tasks.map((task) => {
(jobsConfig.tasks ?? []).map((task) => {
const normalizedTaskSlug = task.slug[0].toUpperCase() + task.slug.slice(1)
const toReturn: JSONSchema4 = {
@@ -110,7 +110,7 @@ export function generateJobsJSONSchemas(
required: ['input', 'output'],
},
},
required: [...jobsConfig.tasks.map((task) => task.slug), 'inline'],
required: [...(jobsConfig.tasks ?? []).map((task) => task.slug), 'inline'],
}
}

View File

@@ -240,7 +240,6 @@ export const getDefaultJobsCollection: (config: Config) => CollectionConfig | nu
export function jobAfterRead({ config, doc }: { config: SanitizedConfig; doc: BaseJob }): BaseJob {
doc.taskStatus = getJobTaskStatus({
jobLog: doc.log || [],
tasksConfig: config.jobs.tasks,
})
return doc
}

View File

@@ -116,7 +116,7 @@ export type JobsConfig = {
/**
* Define all possible tasks here
*/
tasks: TaskConfig<any>[]
tasks?: TaskConfig<any>[]
/**
* Define all the workflows here. Workflows orchestrate the flow of multiple tasks.
*/

View File

@@ -193,7 +193,9 @@ export const getRunTaskFunction = <TIsInline extends boolean>(
let taskConfig: TaskConfig<string>
if (!isInline) {
taskConfig = req.payload.config.jobs.tasks.find((t) => t.slug === taskSlug)
taskConfig =
req.payload.config.jobs.tasks?.length &&
req.payload.config.jobs.tasks.find((t) => t.slug === taskSlug)
if (!taskConfig) {
throw new Error(`Task ${taskSlug} not found in workflow ${job.workflowSlug}`)

View File

@@ -1,4 +1,3 @@
// @ts-strict-ignore
import type { Endpoint, SanitizedConfig } from '../config/types.js'
import { runJobs, type RunJobsArgs } from './operations/runJobs/index.js'
@@ -8,10 +7,10 @@ const configHasJobs = (config: SanitizedConfig): boolean => {
return false
}
if (config.jobs.tasks.length > 0) {
if (config.jobs.tasks?.length > 0) {
return true
}
if (Array.isArray(config.jobs.workflows) && config.jobs.workflows.length > 0) {
if (config.jobs.workflows?.length > 0) {
return true
}
@@ -61,7 +60,7 @@ export const runJobsEndpoint: Endpoint = {
let remainingJobsFromQueried = 0
try {
const result = await runJobs(runJobsArgs)
noJobsRemaining = result.noJobsRemaining
noJobsRemaining = !!result.noJobsRemaining
remainingJobsFromQueried = result.remainingJobsFromQueried
} catch (err) {
req.payload.logger.error({

View File

@@ -1,10 +1,8 @@
// @ts-strict-ignore
import type { TaskConfig, TaskType } from '../config/types/taskTypes.js'
import type { BaseJob, JobTaskStatus } from '../config/types/workflowTypes.js'
type Args = {
jobLog: BaseJob['log']
tasksConfig: TaskConfig<TaskType>[]
}
export const getJobTaskStatus = ({ jobLog }: Args): JobTaskStatus => {