-
-
Notifications
You must be signed in to change notification settings - Fork 455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] SSG with incremental-static-regeneration and revalidate #804
Comments
This would look something like:
Originally posted by @timneutkens in vercel/next.js#11552 That one will be tricky to implement. We could discuss it separately after this RFC is completed.
Implementing
You're right @janus-reith. That removes the need for SQS even though I think AWS still uses a queue behind the scenes for async invocations, but if is abstracting it away from us that's best! My only remaining concern would be latency between regions, say that a user is in us-east-1 and hits one of the edge functions in that region, when invoking the other lambda for background page regeneration what latency are we expected to see? I realise that it won't need to wait for the regeneration lambda to process but the request itself to put the event in the queue what region is that happening and how do we know is not going to a queue somewhere in Originally posted by @danielcondemarin in #355 (comment) To fix it, we need to make the fallback page never cached, so the lambda can return the newly generated page (and cache it) the next time the same route is hit. But we also need to version the pages properly as I realized we are not clearing them properly (we only have one set of pages under static-pages, so subsequent deploys may pick up an old version). Originally posted by @dphang in #798 (comment) Also :
Can one adds this feature to the schedule ? This RFC is older than the v10, back to 9.4 👍 |
Support for incremental static regeneration would be very handy! |
Hey @arelaxend, incremental static regeneration imho is a killer feature of Next.js. Do you have any idea if and by when serverless-next.js will support this? |
Hi, if there is an update on this? Or is there some other method to solve this problem? |
Spent some time thinking about this. My pseudocode is below for anyone that might have time to implement this. This covers both the setting { revalidation: Int } on getStaticProps and { fallback: "blocking" } on getStaticPaths (neither or which are currently handled from my understanding). // below is the try/catch logic that would be inserted inside the response lambda
try {
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property
// this will throw an error if the specified key doesn't exist
const { lastModifiedField } = await s3.headObject({ Bucket, Key: s3Key }).promise()
// if you get to the below, then s3 didn't throw an error, which means
// there is an existing s3 page and you must simply choose whether
// or not to regenerate it in the background
// https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration
if (lastModifiedField - new Date() > getStaticProps.revalidate) {
// if you get to here, then the existing s3 page is stale
// call an async lambda to regenerate the page and upload it to s3
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invokeAsync-property
await lambda.invokeAsync({
FunctionName: "generatePageAndSaveToS3",
InvokeArgs: (req, res)
})
}
// regardless of whether revalidate is undefined or the s3 object is stale
// or not, we simply return the the existing s3 page
return s3Key // i.e. return the existing s3 page
} catch (err) {
// below assumes the error is "specified key doesn't exist"
// https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required
// fallback can be true, false, or blocking
if(getStaticPaths.fallback === true) {
// if fallback is true, we generate the S3 page in the background, but return a fallback page
await lambda.invokeAsync({
FunctionName: "generatePageAndSaveToS3",
InvokeArgs: (req, res)
})
return fallbackPage
} else if(getStaticPaths.fallback === "blocking") {
// if fallback is blocking, then we wait to generate the page
// upload to s3 and return it
const { data, html } = page.renderReqToHTML(req, res)
uploadToS3(data, html)
serve(json)
} else {
return 404page
}
}
// async lambda that gets called if
function generatePageAndSaveToS3(req, res) {
const { data, html } = page.renderReqToHTML(req, res)
await uploadToS3(data, html)
}
For example, if you get 100 requests for a particular page immediately after the revalidation period, the async lambda could get called all 100 times if the first time it was fired the function wasn't able to upload the new page to S3 before the next 99 requests hit
The concurrency limit on a lambda can't be set based on the function arguments as far as I'm aware though, so this would create a bottleneck for ALL page regeneration requests. If you've got dozens or hundreds of ISR pages with and a "revalidation: 1" second, then, you could be calling this lambda more frequently then it could process requests and upload them to S3, which would create an ever-expanding backlog of request For this reason, I think it's better to perhaps let the 99 follow on requests (from the example) simply regenerate the page
In this case, the deduplication id would be composed of the lastModifiedField returned by the s3.headObject().promise() along with the path that the request was made on (e.g. /slug/...). That way, the first request would insert the message into the SQS queue and the other 99 request would automatically be deduplicated. The SQS queue would have the generatePageAndSaveToS3 lambda attached to process the queue request. Based on my understanding of the docs, the deduplication id lasts for 5 mins, so as long as the generatePageAndSaveToS3 can complete the initial request within the 5 minute timeframe, then it should only ever get called once. |
Just confirming my understanding here - incremental static regeneration does not currently work with this repo? |
Hi @avisra |
well... this is a real bummer. my application relies heavily on incremental static regeneration. excuse me while I scramble to find another hosting option... |
Have you attempted this solution yet? |
Are you asking me? If so, no. My application doesn't rely on ISR. I would use it if this repo supported it, but it's not strictly necessary for my use-case. |
I'm looking into implementing this, if nobody else has started the work. I leverage |
@adamelmore sounds good, thanks! Sorry I hadn't a chance to work on this yet. Do let us know if you need any guidance - I think for this feature this would require adding some new SQS / regional Lambda to trigger the incremental static regeneration / revalidate behavior, which can be called from Lambda@Edge using SQS client. |
Where on the roadmap is this placed at this point? It is genuinely one of the best features I've seen from Next. |
Well, I don't know if there's a roadmap, per se; but, on my personal Trello board it's currently in the "Next Week" column 😅 I want this for my own side project, so I will be working on it; it's just a matter of when. I hope to have started in the next week or so, and then go from there. |
I'm interested in paying a bounty to anyone that wants to take this work on. I've got a lot on my plate but really want to see this completed. Offering $1200 USD if anyone that stumbles on this wants to take this on. Message me here or on Twitter for details. |
Upping this to $2000 USD. |
Keen on taking you up on that offer @adamelmore 😁 Just put in a WIP PR here - keen for everyone's feedback. |
I think this can be closed save for any bugs which I will track here: #1098. Thanks all! |
Hi,
Is your feature request related to a problem? Please describe.
When you setup a page
/[id].ts
for SSG withfallback: true
and an API route/api/preview.ts
to enablepreview mode
, when you makes "preview" changes this works pretty well and you can see live changes of the page. 👍Still, changes you make that appears correctly in the
preview mode
does not update thes3 files static-pages/*.html _next/data/*/*.json
accordingly.So whenever you display such a page "publicly" (with preview mode disabled), it does not display the latest changes. What it displays is the latest version of the page stored in s3.
Since currently, the preview mode does not update s3 files, we cannot see the changes with preview mode disabled.
So currently, for a specific page
youdomain/abcde
, the filestatic-page/abcde.html
never updates (this is also true for the corresponding json file). When one makes changes in preview mode, the plugin does not update the static-pagesabcde.html
so the change does not appear publicly.How to reproduce the issue
To reproduce this problem, please follow the steps:
/abced
. It should create_next/data/<id>abced.json
andstatic-pages/abced.html
files in s3 and render the page according to the RFC. 👍/abced
with preview mode ON (with cookies) (to do this, use an API route, e.g./api/preview
)./abced
, as the result, the content shows the updates make in 2/ 👍preview mode cookies
/abced
, since preview mode is OFF this time, the content are not the latest. It displays the result in 1/ instead of displaying the result with modified content in 3/_next/data/<id>abced.json
andstatic-pages/abced.html
in s3. It does not invalidate cloudfront cache neither.Describe the solution you'd like
A good solution requires that when you make changes made in
preview mode
, the next time you render without preview mode the page, it shows the changes.To fix it, we need to make the fallback page never cached
max-age: 0
, so the lambda can return the newly generated page (and cache it) the next time the same route is hit. But we also need to store the html and json files in preview mode for each preview request (RFC STEP 2)Describe alternatives you've considered
The alternative is to force delete those files in s3 and to invalidate cloudfront cache without the plugin. It is not standard, does not follow the RFC and it is a ugly and unsatisfying solution. Per file cache invalidation is not scalable (limit of 3000 concurrent invalidation on AWS) and it has a cost.
Additional context
@dphang discusses a related issue here :
Originally posted by @dphang in #798 (comment)
This discussion triggers a related issue, that is users request cached, still up-to-date versions after a new deployment. This analysis apply to
preview mode
too as described in this thread.Also, #355
A.
The text was updated successfully, but these errors were encountered: