1import * as Effect from "effect/Effect";
2import * as Schedule from "effect/Schedule";
3
4/**
5 * Retry an operation while it fails with a VPC Lattice `ConflictException` —
6 * raised while a resource still has in-flight associations being torn down.
7 * Bounded so a genuinely stuck resource fails fast rather than hanging the
8 * engine.
9 *
10 * The explicit `Effect.Effect<A, E, R>` return annotation is load-bearing:
11 * inlining `Effect.retry` in provider lifecycle code lets `Retry.Return`'s
12 * conditional type survive into declaration emit and widen the provider layer
13 * to `unknown`, breaking every downstream consumer of `AWS.providers()`.
14 */
15export const retryOnConflict = <A, E extends { readonly _tag: string }, R>(
16 effect: Effect.Effect<A, E, R>,
17): Effect.Effect<A, E, R> =>
18 Effect.retry(effect, {
19 while: (e) => e._tag === "ConflictException",
20 schedule: Schedule.max([Schedule.spaced("3 seconds"), Schedule.recurs(10)]),
21 });
22
23/**
24 * Re-run an observation effect until the observed resource is no longer in a
25 * transitional `*_IN_PROGRESS` state (VPC Lattice services and associations
26 * spend a while `CREATE_IN_PROGRESS` and reject updates/deletes until active).
27 * Bounded; explicit return annotation for the declaration-emit reason above.
28 */
29export const waitUntilStable = <
30 A extends { status?: string },
31 E extends { readonly _tag: string },
32 R,
33>(
34 observe: Effect.Effect<A | undefined, E, R>,
35): Effect.Effect<A | undefined, E, R> =>
36 Effect.repeat(observe, {
37 schedule: Schedule.max([Schedule.spaced("3 seconds"), Schedule.recurs(20)]),
38 until: (s) => s === undefined || !(s.status ?? "").endsWith("IN_PROGRESS"),
39 });
40
41/**
42 * Re-run an observation until the resource is observably absent. Delete APIs
43 * commonly return before VPC Lattice removes the resource; a merely stable
44 * `ACTIVE` response is not deletion success. Bounded to about 60 seconds.
45 */
46export const waitUntilAbsent = <A, E extends { readonly _tag: string }, R>(
47 observe: Effect.Effect<A | undefined, E, R>,
48): Effect.Effect<A | undefined, E, R> =>
49 Effect.repeat(observe, {
50 schedule: Schedule.max([Schedule.spaced("2 seconds"), Schedule.recurs(30)]),
51 until: (resource) => resource === undefined,
52 });