@@ -3,16 +3,58 @@ import { IgnorableError } from "@opennextjs/aws/utils/error.js";
33
44import { getCloudflareContext } from "../../cloudflare-context" ;
55
6- export default {
7- name : "do-queue" ,
8- send : async ( msg : QueueMessage ) => {
9- const durableObject = getCloudflareContext ( ) . env . NEXT_CACHE_DO_QUEUE ;
10- if ( ! durableObject ) throw new IgnorableError ( "No durable object binding for cache revalidation" ) ;
6+ interface DurableQueueOptions {
7+ /**
8+ * Enables a regional cache for the queue.
9+ * When enabled, the first request to the queue is cached for `regionalCacheTtlSec` seconds.
10+ * Subsequent similar requests during this period will bypass processing and use the cached result.
11+ * **Note:** Ensure the `MAX_REVALIDATE_CONCURRENCY` environment variable is appropriately increased before enabling this feature.
12+ * In case of an error, cache revalidation may be delayed by up to `regionalCacheTtlSec` seconds.
13+ * @default false
14+ */
15+ enableRegionalCache ?: boolean ;
16+ /**
17+ * The TTL for the regional cache in seconds.
18+ * @default 5
19+ */
20+ regionalCacheTtlSec ?: number ;
21+ }
1122
12- const id = durableObject . idFromName ( msg . MessageGroupId ) ;
13- const stub = durableObject . get ( id ) ;
14- await stub . revalidate ( {
15- ...msg ,
16- } ) ;
17- } ,
18- } satisfies Queue ;
23+ const DEFAULT_QUEUE_CACHE_TTL_SEC = 5 ;
24+
25+ function getCacheKey ( msg : QueueMessage ) {
26+ return new Request (
27+ new URL ( `queue/${ msg . MessageGroupId } /${ msg . MessageDeduplicationId } ` , "http://local.cache" )
28+ ) ;
29+ }
30+
31+ export default ( { enableRegionalCache, regionalCacheTtlSec} : DurableQueueOptions = { } ) => {
32+ return {
33+ name : "durable-queue" ,
34+ send : async ( msg : QueueMessage ) => {
35+ const durableObject = getCloudflareContext ( ) . env . NEXT_CACHE_DO_QUEUE ;
36+ if ( ! durableObject ) throw new IgnorableError ( "No durable object binding for cache revalidation" ) ;
37+
38+ if ( enableRegionalCache ) {
39+ const cacheKey = getCacheKey ( msg ) ;
40+ const cache = await caches . open ( "durable-queue" ) ;
41+ const cachedResponse = await cache . match ( cacheKey ) ;
42+ if ( cachedResponse ) {
43+ return ;
44+ }
45+
46+ // Here we cache the first request to the queue for `regionalCacheTtlSec` seconds
47+ // We want to do it as soon as possible so that subsequent requests can use the cached response
48+ // TODO: Do we really want to cache this before sending the message to the queue? It could be an option to cache it after the message is sent
49+ await cache . put ( cacheKey , new Response ( null , { status : 200 , headers : { "Cache-Control" : `max-age=${ regionalCacheTtlSec ?? DEFAULT_QUEUE_CACHE_TTL_SEC } ` } } ) ) ;
50+
51+ }
52+
53+ const id = durableObject . idFromName ( msg . MessageGroupId ) ;
54+ const stub = durableObject . get ( id ) ;
55+ await stub . revalidate ( {
56+ ...msg ,
57+ } ) ;
58+ } ,
59+ } satisfies Queue ;
60+ }
0 commit comments