opennextjs / opennextjs-aws

Open-source Next.js adapter for AWS
https://open-next.js.org
MIT License
3.9k stars 119 forks source link

OpenNext Ignores force-cache Option on fetch Requests (Data Cache Behavior Differs from Vercel) #493

Closed mlukasik-dev closed 3 weeks ago

mlukasik-dev commented 1 month ago

I recently migrated my project to OpenNext, deploying it with sst@v3. It's a news website built using a custom CMS developed with Next.js. Previously, when hosted on Vercel, nearly all fetch requests to the configuration endpoint were served from cache (with a 99.99% cache hit rate, according to Vercel and our server logs).

However, after the migration, the server is being hit hundreds of times per hour, suggesting that the cache is being bypassed—likely whenever new pages are rendered. This behavior differs significantly from our previous experience on Vercel, where caching worked as expected.

Problem

Questions

  1. What could be causing this cache issue after migrating to OpenNext?
  2. How can I debug or resolve this problem?

I'd greatly appreciate any help, insights, or advice on this issue.

Thank you in advance!

Useful Links

conico974 commented 1 month ago

What version of Next and OpenNext are you using ? If you're on OpenNext 3.0.8, could you test with 3.0.7. I have a feeling that there might be a bug here because of the tag cache and the way it is done in OpenNext. You could also try adding a tag to the fetch request if there is none.

mlukasik-dev commented 1 month ago

Right, I'm using 3.0.8. I'll try to downgrade. Thank you very much for the reply.

conico974 commented 1 month ago

@mlukasik-dev You don't have a tag associated with this fetch call right ? If that's the case the better fix is to just add a tag, this should fix the issue without having to downgrade

mlukasik-dev commented 1 month ago

@mlukasik-dev You don't have a tag associated with this fetch call right ? If that's the case the better fix is to just add a tag, this should fix the issue without having to downgrade

@conico974, I actually have one or two tags on each fetch. I've checked the DynamoDB and they are written correctly.

conico974 commented 1 month ago

I see, in this case i think downgrading will do nothing for your issue. The problem is coming from here https://github.com/sst/open-next/blob/c91c83b5c84c1ea582c03eb23250239954343b64/packages/open-next/src/adapters/cache.ts#L165-L170 We should also add revalidatedAt to 1 otherwise every new page make the fetch data cache stale.

I'll make a PR later today for this

mlukasik-dev commented 1 month ago

@conico974, Thanks for finding a solution so quickly. I didn't even manage to test a downgrade :) Unbelievable!

Btw, while browsing the DynamoDB table, I found another bug with cache tags that makes listing paths by tags unstable and unpredictable. I'll create another issue and link it here.

mlukasik-dev commented 1 month ago

495

mlukasik-dev commented 1 month ago

@conico974, unfortunately the update didn't fix the problem.

In SST I have set openNextVersion to 3.1.1, new DDB lines do have revalidatedAt set to 1.

But the problem persists. I am getting hundreds of requests to the endpoints that should have been cached...

conico974 commented 1 month ago

@mlukasik-dev You'll need to provide a reproduction then

conico974 commented 1 month ago

If you want to debug in your app you should deploy like that OPEN_NEXT_DEBUG=true sst deploy. This will provide a ton of log and might help identify what's wrong

mlukasik-dev commented 1 month ago

@conico974, I've tried to create a very simple Reproduction Example. However, everything works as expected so far.

So I thought: maybe the problem is with the previous cache inside DynamoDB? Shouldn't they be removed or something?

conico974 commented 1 month ago

@mlukasik-dev Here everything is SSG, are you using ISR in your app ?

mlukasik-dev commented 1 month ago

@conico974, then I'm not sure I understand what an ISR means... I thought it was the SSG with pages generated at run time instead of build time (basically my example).

mlukasik-dev commented 1 month ago

For my example, runtime generation is the case because I don't provide the SUPPORTED_LANGS array to generateStaticParams in app/[lang]/layout.tsx.

https://github.com/mlukasik-dev/open-next-data-cache/blob/7d51f247f74509ecf3a2a3fd4f81d63118fddcd4/apps/web/src/app/%5Blang%5D/layout.tsx#L24-L26

conico974 commented 1 month ago

ISR is when you use revalidate either in fetch or with export const revalidate

mlukasik-dev commented 1 month ago

I do use revalidate in one place, but not for the problematic (/config) endpoint.

conico974 commented 1 month ago

Not on this specific fetch, but does the revalidate happens inside a page where this config fetch is done ?

mlukasik-dev commented 1 month ago

Yes, that page has another fetch with options.revalidate set to 86400.

mlukasik-dev commented 1 month ago

I have updated Reproduction Example so it has a fetch with revalidate now: https://github.com/mlukasik-dev/open-next-data-cache/commit/dffa951039cd2d7e4b42e31ff9d23faba1fa3e98

mlukasik-dev commented 1 month ago

I checked the ConfigLambda function logs and confirm the bug is reproduced successfully

conico974 commented 1 month ago

I've deployed your app and it works fine for me. I get only 2 entries in the log even if i navigate to pages that are not generated yet.

There is this issue https://open-next.js.org/common_issues#patch-fetch-behaviour-for-isr-only-for-next1351 that will make it trigger the /config endpoint on ISR request, but in this case that's once every hour. BTW the solution here won't work because the OPEN_NEXT_ISR is not set anymore

sommeeeer commented 1 month ago

I deployed it too. Only got 2 entries in the ConfigLambda log after navigating around to all pages.