diff --git a/rivetkit-typescript/packages/effect/src/internal/ActionDispatcher.test.ts b/rivetkit-typescript/packages/effect/src/internal/ActionDispatcher.test.ts new file mode 100644 index 0000000000..f2b1c4573a --- /dev/null +++ b/rivetkit-typescript/packages/effect/src/internal/ActionDispatcher.test.ts @@ -0,0 +1,40 @@ +import { assert, describe, it } from "@effect/vitest"; +import { Action, Actor } from "@rivetkit/effect"; +import * as Rivetkit from "rivetkit"; +import * as ActionDispatcher from "./ActionDispatcher.ts"; + +const Ping = Action.make("Ping"); + +const dispatchWithoutInstance = (abortSignal: AbortSignal) => { + const handlers = ActionDispatcher.make({ + actor: Actor.make("Probe", { actions: [Ping] }), + getInstance: () => undefined, + }); + const c = { + actorId: "probe", + abortSignal, + } as Rivetkit.ActionContextOf; + return handlers.Ping(c, undefined); +}; + +const assertActorAborted = async (dispatch: Promise) => { + const error = await dispatch.then( + () => assert.fail("expected the action to be rejected"), + (error: unknown) => error, + ); + assert.instanceOf(error, Rivetkit.RivetError); + assert.strictEqual(error.group, "actor"); + assert.strictEqual(error.code, "aborted"); +}; + +describe("internal/ActionDispatcher", () => { + it("rejects an action that reaches a torn-down instance before its signal aborts", async () => { + await assertActorAborted( + dispatchWithoutInstance(new AbortController().signal), + ); + }); + + it("rejects an action that reaches a torn-down instance after its signal aborts", async () => { + await assertActorAborted(dispatchWithoutInstance(AbortSignal.abort())); + }); +}); diff --git a/rivetkit-typescript/packages/effect/src/internal/ActionDispatcher.ts b/rivetkit-typescript/packages/effect/src/internal/ActionDispatcher.ts index eae860841c..db7ae811e6 100644 --- a/rivetkit-typescript/packages/effect/src/internal/ActionDispatcher.ts +++ b/rivetkit-typescript/packages/effect/src/internal/ActionDispatcher.ts @@ -66,10 +66,7 @@ export const make = < const traceMeta = readTraceMeta(meta); const instance = getInstance(c.actorId); - if (!instance) { - if (c.abortSignal.aborted) throw makeActorAbortedError(); - throw new Error("actor instance missing"); - } + if (!instance) throw makeActorAbortedError(); const actionEffect = Effect.gen(function* () { // The handler map is keyed by the same action