Skip to content

Commit 788f799

Browse files
committed
accept direct waitUntil function
1 parent 4478ec6 commit 788f799

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

packages/core/src/utils/flushIfServerless.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ async function flushWithTimeout(timeout: number): Promise<void> {
2525
* The function is async, but in environments that support a `waitUntil` mechanism, it will run synchronously.
2626
*
2727
* This function is aware of the following serverless platforms:
28-
* - Cloudflare: If a Cloudflare context is provided, it will use `ctx.waitUntil()` to flush events.
28+
* - Cloudflare: If a Cloudflare context is provided, it will use `ctx.waitUntil()` to flush events (keeps the `this` context of `ctx`).
29+
* If a `cloudflareWaitUntil` function is provided, it will use that to flush events (looses the `this` context of `ctx`).
2930
* - Vercel: It detects the Vercel environment and uses Vercel's `waitUntil` function.
3031
* - Other Serverless (AWS Lambda, Google Cloud, etc.): It detects the environment via environment variables
3132
* and uses a regular `await flush()`.
@@ -34,15 +35,19 @@ async function flushWithTimeout(timeout: number): Promise<void> {
3435
* @hidden
3536
*/
3637
export async function flushIfServerless(
37-
params: {
38-
timeout?: number;
39-
cloudflareCtx?: MinimalCloudflareContext;
40-
} = {},
38+
params: // eslint-disable-next-line @typescript-eslint/no-explicit-any
39+
| { timeout?: number; cloudflareWaitUntil?: (task: Promise<any>) => void }
40+
| { timeout?: number; cloudflareCtx?: MinimalCloudflareContext },
4141
): Promise<void> {
42-
const { timeout = 2000, cloudflareCtx } = params;
42+
const { timeout = 2000 } = params;
4343

44-
if (cloudflareCtx && typeof cloudflareCtx.waitUntil === 'function') {
45-
cloudflareCtx.waitUntil(flushWithTimeout(timeout));
44+
if ('cloudflareWaitUntil' in params && typeof params?.cloudflareWaitUntil === 'function') {
45+
params.cloudflareWaitUntil(flushWithTimeout(timeout));
46+
return;
47+
}
48+
49+
if ('cloudflareCtx' in params && typeof params.cloudflareCtx?.waitUntil === 'function') {
50+
params.cloudflareCtx.waitUntil(flushWithTimeout(timeout));
4651
return;
4752
}
4853

packages/core/test/lib/utils/flushIfServerless.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe('flushIfServerless', () => {
1616
vi.restoreAllMocks();
1717
});
1818

19-
test('should bind context (preserve `this`) when calling waitUntil', async () => {
19+
test('should bind context (preserve `this`) when calling waitUntil from the Cloudflare execution context', async () => {
2020
const flushMock = vi.spyOn(flushModule, 'flush').mockResolvedValue(true);
2121

2222
// Mock Cloudflare context with `waitUntil` (which should be called if `this` is bound correctly)
@@ -49,6 +49,18 @@ describe('flushIfServerless', () => {
4949
expect(flushMock).toHaveBeenCalledWith(5000);
5050
});
5151

52+
test('should use cloudflare waitUntil when Cloudflare `waitUntil` is provided', async () => {
53+
const flushMock = vi.spyOn(flushModule, 'flush').mockResolvedValue(true);
54+
const mockCloudflareCtx = {
55+
waitUntil: vi.fn(),
56+
};
57+
58+
await flushIfServerless({ cloudflareWaitUntil: mockCloudflareCtx.waitUntil, timeout: 5000 });
59+
60+
expect(mockCloudflareCtx.waitUntil).toHaveBeenCalledTimes(1);
61+
expect(flushMock).toHaveBeenCalledWith(5000);
62+
});
63+
5264
test('should ignore cloudflare context when waitUntil is not a function (and use Vercel waitUntil instead)', async () => {
5365
const flushMock = vi.spyOn(flushModule, 'flush').mockResolvedValue(true);
5466
const vercelWaitUntilSpy = vi.spyOn(vercelWaitUntilModule, 'vercelWaitUntil').mockImplementation(() => {});

0 commit comments

Comments
 (0)