fix: register cache writes with waitUntil so workerd persists them (#73)

void setCached() leaves the R2 put unregistered, and workerd cancels
unregistered pending I/O once the response is sent — the write never
lands, so the caches behind domain overview, domain keyword/page pages,
and SERP research are silently re-fetched (and re-charged) on every
call. Register the writes with waitUntil, matching the pattern already
used in instrumentation.ts and brandLookup.ts.
This commit is contained in:
bookingseo 2026-07-13 23:55:52 +07:00 committed by GitHub
parent 47d638632a
commit 172126aec7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 44 additions and 19 deletions

View File

@ -1,3 +1,4 @@
import { waitUntil } from "cloudflare:workers";
import { buildCacheKey, getCached, setCached } from "@/server/lib/r2-cache";
import { z } from "zod";
import type { BillingCustomerContext } from "@/server/billing/subscription";
@ -90,10 +91,14 @@ async function getOverview(
};
if (result.hasData) {
void setCached(cacheKey, result, DOMAIN_OVERVIEW_TTL_SECONDS).catch(
// waitUntil, not void: workerd cancels unregistered pending I/O once the
// response is sent, so a fire-and-forget put never persists the cache.
waitUntil(
setCached(cacheKey, result, DOMAIN_OVERVIEW_TTL_SECONDS).catch(
(error) => {
console.error("domain.overview.cache-write failed:", error);
},
),
);
}
@ -174,10 +179,15 @@ async function getSuggestedKeywords(
}));
if (keywords.length > 0) {
void setCached(cacheKey, keywords, DOMAIN_OVERVIEW_TTL_SECONDS).catch(
waitUntil(
setCached(cacheKey, keywords, DOMAIN_OVERVIEW_TTL_SECONDS).catch(
(error) => {
console.error("domain.keyword-suggestions.cache-write failed:", error);
console.error(
"domain.keyword-suggestions.cache-write failed:",
error,
);
},
),
);
}

View File

@ -1,3 +1,4 @@
import { waitUntil } from "cloudflare:workers";
import { z } from "zod";
import type { BillingCustomerContext } from "@/server/billing/subscription";
import { createDataforseoClient } from "@/server/lib/dataforseo";
@ -113,10 +114,14 @@ export async function getKeywordsPage(
fetchedAt: new Date().toISOString(),
};
void setCached(cacheKey, result, DOMAIN_KEYWORDS_PAGE_TTL_SECONDS).catch(
// waitUntil, not void: workerd cancels unregistered pending I/O once the
// response is sent, so a fire-and-forget put never persists the cache.
waitUntil(
setCached(cacheKey, result, DOMAIN_KEYWORDS_PAGE_TTL_SECONDS).catch(
(error) => {
console.error("domain.keywords-page.cache-write failed:", error);
},
),
);
return result;

View File

@ -1,3 +1,4 @@
import { waitUntil } from "cloudflare:workers";
import { z } from "zod";
import type { BillingCustomerContext } from "@/server/billing/subscription";
import { createDataforseoClient } from "@/server/lib/dataforseo";
@ -193,10 +194,14 @@ export async function getPagesPage(
fetchedAt: new Date().toISOString(),
};
void setCached(cacheKey, result, DOMAIN_PAGES_PAGE_TTL_SECONDS).catch(
// waitUntil, not void: workerd cancels unregistered pending I/O once the
// response is sent, so a fire-and-forget put never persists the cache.
waitUntil(
setCached(cacheKey, result, DOMAIN_PAGES_PAGE_TTL_SECONDS).catch(
(error) => {
console.error("domain.pages-page.cache-write failed:", error);
},
),
);
return result;

View File

@ -1,3 +1,4 @@
import { waitUntil } from "cloudflare:workers";
import { type SerpLiveItem } from "@/server/lib/dataforseo";
import { buildCacheKey, getCached, setCached } from "@/server/lib/r2-cache";
import type { SerpResultItem } from "@/types/keywords";
@ -91,9 +92,13 @@ async function getSerpLiveAnalysis(
result.reason = "no_organic_results";
}
void setCached(cacheKey, result, SERP_CACHE_TTL_SECONDS).catch((error) => {
// waitUntil, not void: workerd cancels unregistered pending I/O once the
// response is sent, so a fire-and-forget put never persists the cache.
waitUntil(
setCached(cacheKey, result, SERP_CACHE_TTL_SECONDS).catch((error) => {
console.error("keywords.serp.cache-write failed:", error);
});
}),
);
return result;
}