Skip to content

Commit 5dadcce

Browse files
authored
feat: adds new jobs.shouldAutoRun property (#11092)
Adds a `shouldAutoRun` property to the `jobs` config to be able to have fine-grained control over if jobs should be run. This is helpful in cases where you may have many horizontally scaled compute instances, and only one instance should be responsible for running jobs.
1 parent d2fe9b0 commit 5dadcce

File tree

4 files changed

+53
-21
lines changed

4 files changed

+53
-21
lines changed

docs/jobs-queue/queues.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ As mentioned above, you can queue jobs, but the jobs won't run unless a worker p
2929

3030
#### Cron jobs
3131

32-
You can use the jobs.autoRun property to configure cron jobs:
32+
You can use the `jobs.autoRun` property to configure cron jobs:
3333

3434
```ts
3535
export default buildConfig({
@@ -47,6 +47,12 @@ export default buildConfig({
4747
},
4848
// add as many cron jobs as you want
4949
],
50+
shouldAutoRun: async (payload) => {
51+
// Tell Payload if it should run jobs or not.
52+
// This function will be invoked each time Payload goes to pick up and run jobs.
53+
// If this function ever returns false, the cron schedule will be stopped.
54+
return true
55+
}
5056
},
5157
})
5258
```

packages/payload-cloud/src/plugin.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ export const payloadCloudPlugin =
105105
const DEFAULT_CRON_JOB = {
106106
cron: DEFAULT_CRON,
107107
limit: DEFAULT_LIMIT,
108-
queue: 'default (every minute)',
108+
queue: 'default',
109109
}
110+
110111
config.globals = [
111112
...(config.globals || []),
112113
{
@@ -130,26 +131,41 @@ export const payloadCloudPlugin =
130131

131132
const oldAutoRunCopy = config.jobs.autoRun ?? []
132133

134+
const hasExistingAutorun = Boolean(config.jobs.autoRun)
135+
136+
const newShouldAutoRun = async (payload: Payload) => {
137+
if (process.env.PAYLOAD_CLOUD_JOBS_INSTANCE) {
138+
const retrievedGlobal = await payload.findGlobal({
139+
slug: 'payload-cloud-instance',
140+
})
141+
142+
if (retrievedGlobal.instance === process.env.PAYLOAD_CLOUD_JOBS_INSTANCE) {
143+
return true
144+
} else {
145+
process.env.PAYLOAD_CLOUD_JOBS_INSTANCE = ''
146+
}
147+
}
148+
149+
return false
150+
}
151+
152+
if (!config.jobs.shouldAutoRun) {
153+
config.jobs.shouldAutoRun = newShouldAutoRun
154+
}
155+
133156
const newAutoRun = async (payload: Payload) => {
134157
const instance = generateRandomString()
135158

159+
process.env.PAYLOAD_CLOUD_JOBS_INSTANCE = instance
160+
136161
await payload.updateGlobal({
137162
slug: 'payload-cloud-instance',
138163
data: {
139164
instance,
140165
},
141166
})
142167

143-
await waitRandomTime()
144-
145-
const cloudInstance = await payload.findGlobal({
146-
slug: 'payload-cloud-instance',
147-
})
148-
149-
if (cloudInstance.instance !== instance) {
150-
return []
151-
}
152-
if (!config.jobs?.autoRun) {
168+
if (!hasExistingAutorun) {
153169
return [DEFAULT_CRON_JOB]
154170
}
155171

@@ -160,11 +176,3 @@ export const payloadCloudPlugin =
160176

161177
return config
162178
}
163-
164-
function waitRandomTime(): Promise<void> {
165-
const min = 1000 // 1 second in milliseconds
166-
const max = 5000 // 5 seconds in milliseconds
167-
const randomTime = Math.floor(Math.random() * (max - min + 1)) + min
168-
169-
return new Promise((resolve) => setTimeout(resolve, randomTime))
170-
}

packages/payload/src/index.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,9 +729,20 @@ export class BasePayload {
729729
typeof this.config.jobs.autoRun === 'function'
730730
? await this.config.jobs.autoRun(this)
731731
: this.config.jobs.autoRun
732+
732733
await Promise.all(
733734
cronJobs.map((cronConfig) => {
734-
new Cron(cronConfig.cron ?? DEFAULT_CRON, async () => {
735+
const job = new Cron(cronConfig.cron ?? DEFAULT_CRON, async () => {
736+
if (typeof this.config.jobs.shouldAutoRun === 'function') {
737+
const shouldAutoRun = await this.config.jobs.shouldAutoRun(this)
738+
739+
if (!shouldAutoRun) {
740+
job.stop()
741+
742+
return false
743+
}
744+
}
745+
735746
await this.jobs.run({
736747
limit: cronConfig.limit ?? DEFAULT_LIMIT,
737748
queue: cronConfig.queue,

packages/payload/src/queues/config/types/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ export type JobsConfig = {
7676
* a new collection.
7777
*/
7878
jobsCollectionOverrides?: (args: { defaultJobsCollection: CollectionConfig }) => CollectionConfig
79+
/**
80+
* A function that will be executed before Payload picks up jobs which are configured by the `jobs.autorun` function.
81+
* If this function returns true, jobs will be queried and picked up. If it returns false, jobs will not be run.
82+
* @param payload
83+
* @returns boolean
84+
*/
85+
shouldAutoRun?: (payload: Payload) => boolean | Promise<boolean>
7986
/**
8087
* Define all possible tasks here
8188
*/

0 commit comments

Comments
 (0)