@@ -8,8 +8,10 @@ import {
88} from "@opennextjs/aws/utils/error.js" ;
99import { DurableObject } from "cloudflare:workers" ;
1010
11- const MAX_REVALIDATION_BY_DURABLE_OBJECT = 5 ;
11+ const DEFAULT_MAX_REVALIDATION_BY_DURABLE_OBJECT = 5 ;
1212const DEFAULT_REVALIDATION_TIMEOUT_MS = 10_000 ;
13+ const DEFAULT_REVALIDATION_RETRY_INTERVAL_MS = 2_000 ;
14+ const DEFAULT_MAX_REVALIDATION_ATTEMPTS = 6 ;
1315
1416interface FailedState {
1517 msg : QueueMessage ;
@@ -29,8 +31,11 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
2931
3032 service : NonNullable < CloudflareEnv [ "NEXT_CACHE_REVALIDATION_WORKER" ] > ;
3133
32- // TODO: allow this to be configurable - How do we want todo that? env variable? passed down from the queue override ?
33- maxRevalidations = MAX_REVALIDATION_BY_DURABLE_OBJECT ;
34+ // Configurable params
35+ maxRevalidations = DEFAULT_MAX_REVALIDATION_BY_DURABLE_OBJECT ;
36+ revalidationTimeout = DEFAULT_REVALIDATION_TIMEOUT_MS ;
37+ revalidationRetryInterval = DEFAULT_REVALIDATION_RETRY_INTERVAL_MS ;
38+ maxRevalidationAttempts = DEFAULT_MAX_REVALIDATION_ATTEMPTS ;
3439
3540 constructor ( ctx : DurableObjectState , env : CloudflareEnv ) {
3641 super ( ctx , env ) ;
@@ -42,6 +47,22 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
4247
4348 // We restore the state
4449 ctx . blockConcurrencyWhile ( ( ) => this . initState ( ) ) ;
50+
51+ this . maxRevalidations = env . MAX_REVALIDATION_BY_DURABLE_OBJECT
52+ ? parseInt ( env . MAX_REVALIDATION_BY_DURABLE_OBJECT )
53+ : DEFAULT_MAX_REVALIDATION_BY_DURABLE_OBJECT ;
54+
55+ this . revalidationTimeout = env . REVALIDATION_TIMEOUT_MS
56+ ? parseInt ( env . REVALIDATION_TIMEOUT_MS )
57+ : DEFAULT_REVALIDATION_TIMEOUT_MS ;
58+
59+ this . revalidationRetryInterval = env . REVALIDATION_RETRY_INTERVAL_MS
60+ ? parseInt ( env . REVALIDATION_RETRY_INTERVAL_MS )
61+ : DEFAULT_REVALIDATION_RETRY_INTERVAL_MS ;
62+
63+ this . maxRevalidationAttempts = env . MAX_REVALIDATION_ATTEMPTS
64+ ? parseInt ( env . MAX_REVALIDATION_ATTEMPTS )
65+ : DEFAULT_MAX_REVALIDATION_ATTEMPTS ;
4566 }
4667
4768 async revalidate ( msg : QueueMessage ) {
@@ -51,7 +72,7 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
5172 // The route is already in a failed state, it will be retried later
5273 if ( this . routeInFailedState . has ( msg . MessageDeduplicationId ) ) return ;
5374
54- if ( this . ongoingRevalidations . size >= MAX_REVALIDATION_BY_DURABLE_OBJECT ) {
75+ if ( this . ongoingRevalidations . size >= this . maxRevalidations ) {
5576 const ongoingRevalidations = this . ongoingRevalidations . values ( ) ;
5677 // When there is more than the max revalidations, we block concurrency until one of the revalidations finishes
5778 // We still await the promise to ensure the revalidation is completed
@@ -82,7 +103,7 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
82103 "x-prerender-revalidate" : process . env . __NEXT_PREVIEW_MODE_ID ! ,
83104 "x-isr" : "1" ,
84105 } ,
85- signal : AbortSignal . timeout ( DEFAULT_REVALIDATION_TIMEOUT_MS ) ,
106+ signal : AbortSignal . timeout ( this . revalidationTimeout ) ,
86107 } ) ;
87108 // Now we need to handle errors from the fetch
88109 if ( response . status === 200 && response . headers . get ( "x-nextjs-cache" ) !== "REVALIDATED" ) {
@@ -155,20 +176,21 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
155176
156177 async addToFailedState ( msg : QueueMessage ) {
157178 const existingFailedState = this . routeInFailedState . get ( msg . MessageDeduplicationId ) ;
158- let nextAlarm = Date . now ( ) + 2_000 ;
179+ let nextAlarm = Date . now ( ) + this . revalidationRetryInterval ;
159180
160181 let updatedFailedState : FailedState ;
161182
162183 if ( existingFailedState ) {
163- if ( existingFailedState . retryCount >= 6 ) {
184+ if ( existingFailedState . retryCount >= this . maxRevalidationAttempts ) {
164185 // We give up after 6 retries and log the error
165186 error (
166187 `The revalidation for ${ msg . MessageBody . host } ${ msg . MessageBody . url } has failed after 6 retries. It will not be tried again, but subsequent ISR requests will retry.`
167188 ) ;
168189 this . routeInFailedState . delete ( msg . MessageDeduplicationId ) ;
169190 return ;
170191 }
171- nextAlarm = Date . now ( ) + Math . pow ( 2 , existingFailedState . retryCount + 1 ) * 2_000 ;
192+ nextAlarm =
193+ Date . now ( ) + Math . pow ( 2 , existingFailedState . retryCount + 1 ) * this . revalidationRetryInterval ;
172194 updatedFailedState = {
173195 ...existingFailedState ,
174196 retryCount : existingFailedState . retryCount + 1 ,
@@ -203,7 +225,7 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
203225 ) ;
204226 if ( nextAlarmToSetup < Date . now ( ) ) {
205227 // We don't want to set an alarm in the past
206- nextAlarmToSetup = Date . now ( ) + 2_000 ;
228+ nextAlarmToSetup = Date . now ( ) + this . revalidationRetryInterval ;
207229 }
208230 await this . ctx . storage . setAlarm ( nextAlarmToSetup ) ;
209231 }
0 commit comments