fix: delete scheduled publish jobs when deleting documents (#10584)
### What? When a document gets deleted we are not cleaning up jobs that would fail if the document doesn't exist. This change makes an extra call to the DB to delete any incomplete jobs for the document. ### Why? The jobs queue will error and retry needlessly unless these are purged. ### How? Adds a call to delete jobs from the delete operation.
This commit is contained in:
@@ -23,6 +23,7 @@ import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import { deleteCollectionVersions } from '../../versions/deleteCollectionVersions.js'
|
||||
import { deleteScheduledPublishJobs } from '../../versions/deleteScheduledPublishJobs.js'
|
||||
import { buildAfterOperation } from './utils.js'
|
||||
|
||||
export type Arguments = {
|
||||
@@ -177,6 +178,18 @@ export const deleteOperation = async <
|
||||
})
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Delete scheduled posts
|
||||
// /////////////////////////////////////
|
||||
if (collectionConfig.versions?.drafts && collectionConfig.versions.drafts.schedulePublish) {
|
||||
await deleteScheduledPublishJobs({
|
||||
id,
|
||||
slug: collectionConfig.slug,
|
||||
payload,
|
||||
req,
|
||||
})
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Delete document
|
||||
// /////////////////////////////////////
|
||||
|
||||
@@ -19,6 +19,7 @@ import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
import { initTransaction } from '../../utilities/initTransaction.js'
|
||||
import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import { deleteCollectionVersions } from '../../versions/deleteCollectionVersions.js'
|
||||
import { deleteScheduledPublishJobs } from '../../versions/deleteScheduledPublishJobs.js'
|
||||
import { buildAfterOperation } from './utils.js'
|
||||
|
||||
export type Arguments = {
|
||||
@@ -155,6 +156,18 @@ export const deleteByIDOperation = async <TSlug extends CollectionSlug, TSelect
|
||||
})
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Delete scheduled posts
|
||||
// /////////////////////////////////////
|
||||
if (collectionConfig.versions?.drafts && collectionConfig.versions.drafts.schedulePublish) {
|
||||
await deleteScheduledPublishJobs({
|
||||
id,
|
||||
slug: collectionConfig.slug,
|
||||
payload,
|
||||
req,
|
||||
})
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Delete document
|
||||
// /////////////////////////////////////
|
||||
|
||||
@@ -21,8 +21,9 @@ export const deleteCollectionVersions = async ({ id, slug, payload, req }: Args)
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
payload.logger.error(
|
||||
`There was an error removing versions for the deleted ${slug} document with ID ${id}.`,
|
||||
)
|
||||
payload.logger.error({
|
||||
err,
|
||||
msg: `There was an error removing versions for the deleted ${slug} document with ID ${id}.`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
60
packages/payload/src/versions/deleteScheduledPublishJobs.ts
Normal file
60
packages/payload/src/versions/deleteScheduledPublishJobs.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { PayloadRequest } from '../types/index.js'
|
||||
|
||||
import { type Payload } from '../index.js'
|
||||
|
||||
type Args = {
|
||||
id?: number | string
|
||||
payload: Payload
|
||||
req?: PayloadRequest
|
||||
slug: string
|
||||
}
|
||||
|
||||
export const deleteScheduledPublishJobs = async ({
|
||||
id,
|
||||
slug,
|
||||
payload,
|
||||
req,
|
||||
}: Args): Promise<void> => {
|
||||
try {
|
||||
await payload.db.deleteMany({
|
||||
collection: 'payload-jobs',
|
||||
req,
|
||||
where: {
|
||||
and: [
|
||||
// only want to delete jobs have not run yet
|
||||
{
|
||||
completedAt: {
|
||||
exists: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
processing: {
|
||||
equals: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
'input.doc.value': {
|
||||
equals: id,
|
||||
},
|
||||
},
|
||||
{
|
||||
'input.doc.relationTo': {
|
||||
equals: slug,
|
||||
},
|
||||
},
|
||||
// data.type narrows scheduled publish jobs in case of another job having input.doc.value
|
||||
{
|
||||
taskSlug: {
|
||||
equals: 'schedulePublish',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
payload.logger.error({
|
||||
err,
|
||||
msg: `There was an error deleting scheduled publish jobs from the queue for ${slug} document with ID ${id}.`,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1944,6 +1944,94 @@ describe('Versions', () => {
|
||||
expect(retrieved._status).toStrictEqual('draft')
|
||||
})
|
||||
|
||||
it('should delete scheduled jobs after a document is deleted', async () => {
|
||||
const draft = await payload.create({
|
||||
collection: draftCollectionSlug,
|
||||
data: {
|
||||
title: 'my doc to publish in the future',
|
||||
description: 'hello',
|
||||
},
|
||||
draft: true,
|
||||
})
|
||||
|
||||
expect(draft._status).toStrictEqual('draft')
|
||||
|
||||
const currentDate = new Date()
|
||||
|
||||
await payload.jobs.queue({
|
||||
task: 'schedulePublish',
|
||||
waitUntil: new Date(currentDate.getTime() + 3000),
|
||||
input: {
|
||||
type: 'publish',
|
||||
doc: {
|
||||
relationTo: draftCollectionSlug,
|
||||
value: draft.id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
await payload.delete({
|
||||
collection: draftCollectionSlug,
|
||||
where: {
|
||||
id: { equals: draft.id },
|
||||
},
|
||||
})
|
||||
|
||||
const { docs } = await payload.find({
|
||||
collection: 'payload-jobs',
|
||||
where: {
|
||||
'input.doc.value': {
|
||||
equals: draft.id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(docs[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should delete scheduled jobs after a document is deleted by ID', async () => {
|
||||
const draft = await payload.create({
|
||||
collection: draftCollectionSlug,
|
||||
data: {
|
||||
title: 'my doc to publish in the future',
|
||||
description: 'hello',
|
||||
},
|
||||
draft: true,
|
||||
})
|
||||
|
||||
expect(draft._status).toStrictEqual('draft')
|
||||
|
||||
const currentDate = new Date()
|
||||
|
||||
await payload.jobs.queue({
|
||||
task: 'schedulePublish',
|
||||
waitUntil: new Date(currentDate.getTime() + 3000),
|
||||
input: {
|
||||
type: 'publish',
|
||||
doc: {
|
||||
relationTo: draftCollectionSlug,
|
||||
value: draft.id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
await payload.delete({
|
||||
collection: draftCollectionSlug,
|
||||
id: draft.id,
|
||||
})
|
||||
|
||||
const { docs } = await payload.find({
|
||||
collection: 'payload-jobs',
|
||||
where: {
|
||||
'input.doc.value': {
|
||||
equals: draft.id,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(docs[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should allow global scheduled publish', async () => {
|
||||
const draft = await payload.updateGlobal({
|
||||
slug: draftGlobalSlug,
|
||||
|
||||
Reference in New Issue
Block a user