Skip to content

Commit

Permalink
fix(ssr): Wait async API context handling to reset status on error (404)
Browse files Browse the repository at this point in the history
  • Loading branch information
leomp12 committed Apr 26, 2024
1 parent a6e3f18 commit 3858206
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
46 changes: 40 additions & 6 deletions packages/ssr/src/lib/serve-storefront.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,11 @@ export default async (req: Request, res: Response) => {
const _writeHead = res.writeHead;
/* eslint-disable prefer-rest-params */
// @ts-ignore
res.writeHead = function writeHead(status: number, headers?: OutgoingHttpHeaders) {
res.writeHead = async function writeHead(status: number, headers?: OutgoingHttpHeaders) {
let resolveHeadersSent: ((v: any) => any) | undefined;
const waitingHeadersSent = new Promise((resolve) => {
resolveHeadersSent = resolve;
});
if (canSetLinkHeader && status === 200 && headers && cssFilepath) {
// https://community.cloudflare.com/t/early-hints-need-more-data-before-switching-over/342888/21
const cssLink = `<${(assetsPrefix || '')}${cssFilepath}>; rel=preload; as=style`;
Expand All @@ -292,14 +296,43 @@ export default async (req: Request, res: Response) => {
const sid = headers['x-sid'];
if (sessions[sid]) {
headers['x-sid'] += '_';
/* Wait to reset status for async context error handling */
const { fetchingApiContext } = sessions[sid];
const waitingStatus: Promise<boolean> = fetchingApiContext
? new Promise((resolve) => {
fetchingApiContext.finally(() => {
const apiContextStatus = sessions[sid].apiContextError?.statusCode;
if (apiContextStatus >= 400 && status === 200) {
status = apiContextStatus;
}
resolve(true);
});
})
: Promise.resolve(false);
const _write = res.write;
const writes: Promise<any>[] = [];
// @ts-ignore
res.write = function write(...args: any) {
writes.push(new Promise((resolve) => {
waitingHeadersSent.finally(() => {
_write.apply(res, args);
resolve(null);
});
}));
};
const _end = res.end;
// @ts-ignore
res.end = function end(...args: any) {
if (sessions[sid]._timer) clearTimeout(sessions[sid]._timer);
sessions[sid] = null;
delete sessions[sid];
_end.apply(res, args);
res.end = async function end(...args: any) {
await waitingHeadersSent;
setTimeout(async () => {
await Promise.all(writes);
if (sessions[sid]._timer) clearTimeout(sessions[sid]._timer);
sessions[sid] = null;
delete sessions[sid];
_end.apply(res, args);
}, 1);
};
await waitingStatus;
}
}
if (headers && BUNNYNET_API_KEY && DEPLOY_RAND) {
Expand All @@ -309,6 +342,7 @@ export default async (req: Request, res: Response) => {
delete headers['CDN-Tag'];
}
_writeHead.apply(res, [status, headers]);
resolveHeadersSent?.(null);
};

/*
Expand Down
6 changes: 5 additions & 1 deletion packages/storefront/src/lib/ssr-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ if (!globalThis.$apiPrefetchEndpoints) {
}
const sessions: Record<string, {
url: URL,
fetchingApiContext?: Promise<any>,
apiContext?: StorefrontApiContext,
apiContextError?: ApiError;
_timer?: NodeJS.Timeout,
}> = {};
// Internal global just to early clear session objects from memory
Expand Down Expand Up @@ -233,10 +235,12 @@ const loadRouteContext = async (
reject(err);
} else {
apiContext.error = err;
sessions[sid].apiContextError = err;
resolve(null);
}
});
}) as Promise<null>;
sessions[sid].fetchingApiContext = fetchingApiContext;
if (prefetchingsIndex > -1) {
apiPrefetchings[prefetchingsIndex] = fetchingApiContext;
}
Expand Down Expand Up @@ -282,7 +286,7 @@ const loadRouteContext = async (
Astro.response.status = status;
err.responseHTML = `<head>
<meta http-equiv="refresh" content="0;
url=/~fallback?status=${status}&url=${encodeURIComponent(urlPath)}"/>
url=/~fallback?status=${status}&url=${encodeURIComponent(urlPath)}&__"/>
</head>
<body></body>`;
throw err;
Expand Down

0 comments on commit 3858206

Please sign in to comment.