1
- import { debug , error } from "@opennextjs/aws/adapters/logger.js" ;
1
+ import { debug , error , warn } from "@opennextjs/aws/adapters/logger.js" ;
2
2
import type { QueueMessage } from "@opennextjs/aws/types/overrides" ;
3
3
import {
4
4
FatalError ,
@@ -73,6 +73,11 @@ export class DOQueueHandler extends DurableObject<CloudflareEnv> {
73
73
}
74
74
75
75
async revalidate ( msg : QueueMessage ) {
76
+ if ( this . ongoingRevalidations . size > 2 * this . maxRevalidations ) {
77
+ warn (
78
+ `Your durable object has 2 times the maximum number of revalidations (${ this . maxRevalidations } ) in progress. If this happens often, you should consider increasing the NEXT_CACHE_DO_QUEUE_MAX_REVALIDATION or the number of durable objects with the MAX_REVALIDATE_CONCURRENCY env var.`
79
+ ) ;
80
+ }
76
81
// If there is already an ongoing revalidation, we don't need to revalidate again
77
82
if ( this . ongoingRevalidations . has ( msg . MessageDeduplicationId ) ) return ;
78
83
@@ -87,22 +92,21 @@ export class DOQueueHandler extends DurableObject<CloudflareEnv> {
87
92
debug (
88
93
`The maximum number of revalidations (${ this . maxRevalidations } ) is reached. Blocking until one of the revalidations finishes.`
89
94
) ;
90
- const ongoingRevalidations = this . ongoingRevalidations . values ( ) ;
91
- // When there is more than the max revalidations, we block concurrency until one of the revalidations finishes
92
- // We still await the promise to ensure the revalidation is completed
93
- // This is fine because the queue itself run inside a waitUntil
94
- await this . ctx . blockConcurrencyWhile ( async ( ) => {
95
+ // TODO: need more investigation
96
+ // We don't use `blockConcurrencyWhile` here because it block the whole durable object for 30 seconds
97
+ // if we exceed the max revalidations too fast
98
+ while ( this . ongoingRevalidations . size >= this . maxRevalidations ) {
99
+ const ongoingRevalidations = this . ongoingRevalidations . values ( ) ;
95
100
debug ( `Waiting for one of the revalidations to finish` ) ;
96
101
await Promise . race ( ongoingRevalidations ) ;
97
- } ) ;
102
+ }
98
103
}
99
104
100
105
const revalidationPromise = this . executeRevalidation ( msg ) ;
101
106
102
107
// We store the promise to dedupe the revalidation
103
108
this . ongoingRevalidations . set ( msg . MessageDeduplicationId , revalidationPromise ) ;
104
109
105
- // TODO: check if the object stays up during waitUntil so that the internal state is maintained
106
110
this . ctx . waitUntil ( revalidationPromise ) ;
107
111
}
108
112
@@ -121,6 +125,7 @@ export class DOQueueHandler extends DurableObject<CloudflareEnv> {
121
125
"x-prerender-revalidate" : process . env . __NEXT_PREVIEW_MODE_ID ! ,
122
126
"x-isr" : "1" ,
123
127
} ,
128
+ // This one is kind of problematic, it will always show the wall time of the revalidation to `this.revalidationTimeout`
124
129
signal : AbortSignal . timeout ( this . revalidationTimeout ) ,
125
130
} ) ;
126
131
// Now we need to handle errors from the fetch
@@ -260,6 +265,7 @@ export class DOQueueHandler extends DurableObject<CloudflareEnv> {
260
265
this . sql . exec ( "CREATE TABLE IF NOT EXISTS sync (id TEXT PRIMARY KEY, lastSuccess INTEGER, buildId TEXT)" ) ;
261
266
262
267
// Before doing anything else, we clear the DB for any potential old data
268
+ // TODO: extract this to a function so that it could be called by the user at another time than init
263
269
this . sql . exec ( "DELETE FROM failed_state WHERE buildId != ?" , process . env . __NEXT_BUILD_ID ) ;
264
270
this . sql . exec ( "DELETE FROM sync WHERE buildId != ?" , process . env . __NEXT_BUILD_ID ) ;
265
271
0 commit comments