Skip to content

Commit 43d7de3

Browse files
committed
commit
1 parent 8ca6282 commit 43d7de3

2 files changed

Lines changed: 72 additions & 12 deletions

File tree

packages/payload/src/queues/operations/runJobs/index.ts

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -330,23 +330,46 @@ export const runJobs = async (args: RunJobsArgs): Promise<RunJobsResult> => {
330330
}
331331
const jobReq = isolateObjectProperty(req, 'transactionID')
332332

333-
const workflowConfig: WorkflowConfig =
334-
job.workflowSlug && jobsConfig.workflows?.length
335-
? jobsConfig.workflows.find(({ slug }) => slug === job.workflowSlug)!
336-
: {
337-
slug: 'singleTask',
338-
handler: async ({ job, tasks }) => {
339-
await tasks[job.taskSlug as string]!('1', {
340-
input: job.input,
341-
})
342-
},
343-
}
333+
let workflowConfig: undefined | WorkflowConfig = undefined
334+
335+
if (job.workflowSlug && jobsConfig.workflows?.length) {
336+
workflowConfig = jobsConfig.workflows.find(({ slug }) => slug === job.workflowSlug)
337+
} else if (job.taskSlug && jobsConfig.tasks?.length) {
338+
const taskExists = jobsConfig.tasks.some(({ slug }) => slug === job.taskSlug)
339+
if (taskExists) {
340+
workflowConfig = {
341+
slug: 'singleTask',
342+
handler: async ({ job, tasks }) => {
343+
await tasks[job.taskSlug as string]!('1', {
344+
input: job.input,
345+
})
346+
},
347+
}
348+
}
349+
}
344350

345351
if (!workflowConfig) {
352+
const slugLabel = job.taskSlug ? `task '${job.taskSlug}'` : `workflow '${job.workflowSlug}'`
353+
const errorMessage = `Job references ${slugLabel}, which is not registered in payload.config.jobs. The slug may have been removed from config after the job was queued.`
354+
355+
if (!silent || (typeof silent === 'object' && !silent.error)) {
356+
payload.logger.error({
357+
msg: `Error running job ${job.workflowSlug || `Task: ${job.taskSlug}`} id: ${job.id} - ${errorMessage}`,
358+
})
359+
}
360+
361+
const updateJob = getUpdateJobFunction(job, jobReq)
362+
await updateJob({
363+
error: { message: errorMessage },
364+
hasError: true,
365+
processing: false,
366+
totalTried: (job.totalTried ?? 0) + 1,
367+
})
368+
346369
return {
347370
id: job.id,
348371
result: {
349-
status: 'error',
372+
status: 'error-reached-max-retries',
350373
},
351374
} // Skip jobs with no workflow configuration
352375
}

test/queues/int.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,43 @@ describe('Queues - Payload', () => {
938938
expect(allSimples.docs[0]?.title).toBe('from single task')
939939
})
940940

941+
describe('when a queued task slug is no longer registered in config', () => {
942+
let originalTasks: typeof payload.config.jobs.tasks
943+
944+
beforeEach(() => {
945+
originalTasks = payload.config.jobs.tasks
946+
})
947+
948+
afterEach(() => {
949+
payload.config.jobs.tasks = originalTasks
950+
})
951+
952+
it('should permanently fail the job after one attempt instead of retrying forever', async () => {
953+
payload.config.jobs.deleteJobOnComplete = false
954+
955+
const job = await payload.jobs.queue({
956+
task: 'CreateSimple',
957+
input: {
958+
message: 'queued before task removal',
959+
},
960+
})
961+
962+
// Simulate a deploy that removed the 'CreateSimple' task from config
963+
payload.config.jobs.tasks = originalTasks!.filter((t) => t.slug !== 'CreateSimple')
964+
965+
await payload.jobs.run({ silent: true })
966+
967+
const jobAfterRun = await payload.findByID({
968+
collection: 'payload-jobs',
969+
id: job.id,
970+
})
971+
972+
expect(jobAfterRun.hasError).toBe(true)
973+
expect(jobAfterRun.processing).toBe(false)
974+
expect(jobAfterRun.totalTried).toBe(1)
975+
})
976+
})
977+
941978
it('can queue and run via the endpoint single tasks without workflows', async () => {
942979
const workflowsRef = payload.config.jobs.workflows
943980
delete payload.config.jobs.workflows

0 commit comments

Comments
 (0)