1import { waitUntil as nativeWaitUntil } from "@neon/functions";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import * as Scope from "effect/Scope";
5import type { RuntimeContext } from "../RuntimeContext.ts";
6
7/**
8 * Run bounded post-response work with its own scope. Failures are logged.
9 * Neon limits waitUntil work to fifteen minutes; this is not a durable job.
10 */
11export const waitUntil = <A, E, R>(
12 effect: Effect.Effect<A, E, R>,
13): Effect.Effect<void, never, RuntimeContext | Exclude<R, Scope.Scope>> =>
14 Effect.gen(function* () {
15 const context = yield* Effect.context<Exclude<R, Scope.Scope>>();
16 const memoMap = yield* Layer.makeMemoMap;
17 yield* Effect.sync(() =>
18 nativeWaitUntil(
19 Effect.runPromiseWith(context)(
20 effect.pipe(
21 Effect.scoped,
22 Effect.provideService(Layer.CurrentMemoMap, memoMap),
23 Effect.timeout("15 minutes"),
24 Effect.tapCause(() =>
25 Effect.logError("Neon waitUntil task failed"),
26 ),
27 ),
28 ),
29 ),
30 );
31 });