| @@ -3,6 +3,7 @@ · 2 unmodified lines |
| 3 | 3 | // --------------------------------------------------------------------------- |
| 4 | 4 | |
| 5 | 5 | import { Effect } from "effect"; |
| 6 | +import { waitUntil } from "cloudflare:workers"; |
| 6 | 7 | |
| 7 | 8 | import { WorkOSClient } from "../../auth/workos"; |
| 8 | 9 | import { AutumnService } from "./service"; |
| @@ -38,9 +39,9 @@ export const reportMemberSeats = ( · 29 unmodified lines |
| 38 | 39 | /** |
| 39 | 40 | * Fork `reportMemberSeats` off the calling request, mirroring how execution |
| 40 | 41 | * tracking is forked: billing must never stall or fail a user-facing |
| 41 | | − * request. Only boot-scoped services are captured (WorkOS + Autumn — no |
| 42 | | − * request-scoped resources), so the forked fiber cannot outlive anything it |
| 43 | | − * depends on. |
| 42 | + * request. Cloudflare owns the promise through waitUntil, so the recount can |
| 43 | + * finish after the response. Only boot-scoped WorkOS and Autumn services are |
| 44 | + * captured. |
| 44 | 45 | */ |
| 45 | 46 | export const forkReportMemberSeats = ( |
| 46 | 47 | organizationId: string, |
| @@ -48,6 +49,6 @@ export const forkReportMemberSeats = ( · 1 unmodified line |
| 48 | 49 | Effect.gen(function* () { |
| 49 | 50 | const ctx = yield* Effect.context<WorkOSClient | AutumnService>(); |
| 50 | 51 | yield* Effect.sync(() => { |
| 51 | | − Effect.runForkWith(ctx)(reportMemberSeats(organizationId)); |
| 52 | + waitUntil(Effect.runPromiseWith(ctx)(reportMemberSeats(organizationId))); |
| 52 | 53 | }); |
| 53 | 54 | }); |