Skip to content

Commit 2dc337e

Browse files
committed
queue cache
1 parent cef5e03 commit 2dc337e

File tree

2 files changed

+55
-13
lines changed

2 files changed

+55
-13
lines changed

examples/e2e/app-router/open-next.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ export default defineCloudflareConfig({
1414
numberOfHardReplicas: 2,
1515
},
1616
}),
17-
queue: doQueue,
17+
queue: doQueue({ enableRegionalCache: true, regionalCacheTtlSec: 5 }),
1818
});

packages/cloudflare/src/api/overrides/queue/do-queue.ts

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,58 @@ import { IgnorableError } from "@opennextjs/aws/utils/error.js";
33

44
import { 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

Comments
 (0)