payload icon indicating copy to clipboard operation
payload copied to clipboard

fetch results are cached across job runs — even with cache: 'no-store'

Open cloud2303 opened this issue 2 months ago • 4 comments

Describe the Bug

When running a recurring Payload job using TaskConfig, the same fetch() request seems to reuse cached results between job runs, even though cache: 'no-store' is explicitly passed to fetch.

This behavior causes scheduled jobs to keep processing the same response data every time instead of fetching a fresh response from the remote API.

Link to the code that reproduces this issue

https://github.com/cloud2303/payload-cache

Reproduction Steps

Example job definition:

export const RefreshWeChatToken: TaskConfig<'refreshWeChatToken'> = {
  slug: 'refreshWeChatToken',
  schedule: [
    {
      cron: '*/10 * * * * *',
      queue: 'second',
    },
  ],
  retries: 0,
  label: 'referesh token',
  handler: async ({ req }) => {
    // each time return different value
    const url = 'http://127.0.0.1:4523/m2/6882259-6597789-default/362218398'
    const response = await fetch(url, { cache: 'no-cache' })
    const res = await response.json()
    console.log(res)
    return res
  },
}

Logs output repeatedly every 10 seconds with identical data:

[14:49:30] INFO: Running 1 jobs.
    new: 1
    retrying: 0
{ access_token: 'adipisicing', expires_in: 79 }
[14:49:40] INFO: Running 1 jobs.
    new: 1
    retrying: 0
{ access_token: 'adipisicing', expires_in: 79 }
[14:49:50] INFO: Running 1 jobs.
    new: 1
    retrying: 0
{ access_token: 'adipisicing', expires_in: 79 }
[14:50:00] INFO: Running 1 jobs.
    new: 1
    retrying: 0
{ access_token: 'adipisicing', expires_in: 79 }
...

Even though the job reruns and fetch uses cache: 'no-store', the data returned never changes. This happens even when:

The mock server returns dynamic data when called externally.

The job handler is re-run by the internal Payload cron scheduler.

Which area(s) are affected? (Select all that apply)

Not sure

Environment Info

Binaries:
  Node: 24.10.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  payload: 3.60.0
  next: 15.4.4
  @payloadcms/db-sqlite: 3.60.0
  @payloadcms/drizzle: 3.60.0
  @payloadcms/email-nodemailer: 3.60.0
  @payloadcms/graphql: 3.60.0
  @payloadcms/next/utilities: 3.60.0
  @payloadcms/payload-cloud: 3.60.0
  @payloadcms/richtext-lexical: 3.60.0
  @payloadcms/translations: 3.60.0
  @payloadcms/ui/shared: 3.60.0
  react: 19.1.0
  react-dom: 19.1.0
Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Enterprise
  Available memory (MB): 16099
  Available CPU cores: 12

cloud2303 avatar Oct 17 '25 06:10 cloud2303

Also having this problem. Running 3.64.0.

andershermansen avatar Nov 27 '25 14:11 andershermansen

I believe it's running in Nodejs, and it's not using Nextjs' fetch function, so make sure to add a timestamp, like

const cacheBuster = Date.now()
const url = `https://api.example.com/?_t=${cacheBuster}

hristokoev avatar Nov 27 '25 14:11 hristokoev

I believe it's running in Nodejs, and it's not using Nextjs' fetch function, so make sure to add a timestamp, like

Thanks for the workaround. Let's look further for the root cause here. Because it should not cache, especially not with 'no-store' set.

andershermansen avatar Nov 27 '25 14:11 andershermansen

Next.js extends the fetch() function with { cache: 'force-cache' | 'no-store' }, but the default fetch() function doesn't have it. So if cron jobs are running as Node.js process as a separate instance outside of Next.js context, it'd make sense. Maybe there's a way to bring the extended Next.js fetch() function.

hristokoev avatar Nov 27 '25 14:11 hristokoev