Skip to content

Artifacts.cached never settles waiters when the effect fails, hanging plan #2981

Closed

Description

@juliusmarminge

What happens

Artifacts.cached(id) never settles its Deferred when the wrapped effect fails. The first caller gets the failure; every later caller with the same id awaits Deferred.await(deferred) forever.

// packages/alchemy/src/Artifacts.ts
yield* artifacts.set(id, Deferred.await(deferred));
const result = yield* eff;          // on failure, deferred is never completed
yield* Deferred.succeed(deferred, result);

Repro (beta.85):

const once = Effect.fail("boom").pipe(Artifacts.cached("k"));
const first = yield* Effect.exit(once);                                    // Failure
const second = yield* Effect.exit(once).pipe(Effect.timeoutOption("2 seconds")); // None: hung

How this hangs a deploy

During plan, a resource with persisted state is diffed twice: once in resolveResource (stable attributes for downstream consumers) and once in diffResource. Drizzle.Schema caches detectDrift with Artifacts.cached, so when the first diff fails (for example #2980), the second waits forever, and so does every resource downstream of the schema. alchemy deploy sits at "Computing plan" until CI kills it, with no error. In --no-input mode nothing shows which resource is stuck, since failed diffs never emit plan.resource.completed.

Fix we are running

Settle waiters on any exit:

 yield* artifacts.set(id, Deferred.await(deferred));
-const result = yield* eff;
-yield* Deferred.succeed(deferred, result);
+// Settle waiters on failure too, or every later caller hangs.
+const result = yield* eff.pipe(Effect.onExit((exit) => Deferred.done(deferred, exit)));
 yield* artifacts.set(id, result);

(In the TypeScript source the Deferred would need the error type, Deferred.make<A, Err>().) It may also be worth not caching failures at all, so a later caller retries instead of replaying the error.

Activity

  1. sam-goodwin commented on Nov 4, 2026

    @sam-goodwin
    Member

    @BlankParticle you changed something here right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions