mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 09:29:38 +02:00
Fail pending request responses on stop
This commit is contained in:
parent
0fb943c0ef
commit
1218e827d4
5 changed files with 95 additions and 12 deletions
|
|
@ -408,8 +408,8 @@ describe("Effect-native messaging runtime", () => {
|
|||
it.effect(
|
||||
"fails request-response calls with a typed timeout",
|
||||
Effect.fnUntraced(function* () {
|
||||
const responseConsumer = new ScriptedConsumer<string>();
|
||||
const backend = new RuntimeBackend(responseConsumer as BackendConsumer<unknown>);
|
||||
const responseConsumer = new ScriptedConsumer<unknown>();
|
||||
const backend = new RuntimeBackend(responseConsumer);
|
||||
|
||||
const error = yield* Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -440,6 +440,41 @@ describe("Effect-native messaging runtime", () => {
|
|||
}),
|
||||
);
|
||||
|
||||
it.effect(
|
||||
"fails pending request-response calls when the runtime stops",
|
||||
Effect.fnUntraced(function* () {
|
||||
const responseConsumer = new ScriptedConsumer<string>();
|
||||
const backend = new RuntimeBackend(responseConsumer as BackendConsumer<unknown>);
|
||||
|
||||
const error = yield* Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const requestor = yield* makeEffectRequestResponseFromPubSub<string, string>(
|
||||
PubSub.fromBackend(backend),
|
||||
{
|
||||
...defaultMessagingRuntimeConfig,
|
||||
consumerReceiveTimeoutMs: 1,
|
||||
},
|
||||
{
|
||||
requestTopic: "tg.test.request",
|
||||
responseTopic: "tg.test.response",
|
||||
subscription: "sub",
|
||||
},
|
||||
);
|
||||
const fiber = yield* requestor.request("request", { timeoutMs: 1_000 }).pipe(Effect.forkChild);
|
||||
yield* TestClock.adjust(Duration.millis(5));
|
||||
yield* requestor.stop;
|
||||
return yield* Fiber.join(fiber).pipe(Effect.flip);
|
||||
}),
|
||||
);
|
||||
|
||||
expect(error).toMatchObject({
|
||||
_tag: "MessagingLifecycleError",
|
||||
operation: "stop",
|
||||
resource: "tg.test.request:tg.test.response",
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
it.effect(
|
||||
"owns Flow lifecycle through a scoped Effect boundary",
|
||||
Effect.fnUntraced(function* () {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { Context, Duration, Effect, Fiber, Layer, Queue, Ref, Result, Schedule, Scope, Stream } from "effect";
|
||||
import { Context, Deferred, Duration, Effect, Fiber, Layer, Queue, Ref, Result, Schedule, Scope, Stream } from "effect";
|
||||
import * as O from "effect/Option";
|
||||
import * as S from "effect/Schema";
|
||||
import type {
|
||||
|
|
@ -92,7 +92,7 @@ export interface EffectRequestResponse<TReq, TRes> {
|
|||
readonly request: <E = never, R = never>(
|
||||
request: TReq,
|
||||
options?: EffectRequestOptions<TRes, E, R>,
|
||||
) => Effect.Effect<TRes, MessagingDeliveryError | MessagingTimeoutError | E, R>;
|
||||
) => Effect.Effect<TRes, MessagingDeliveryError | MessagingLifecycleError | MessagingTimeoutError | E, R>;
|
||||
readonly stop: Effect.Effect<void, MessagingLifecycleError | MessagingDeliveryError>;
|
||||
}
|
||||
|
||||
|
|
@ -476,12 +476,17 @@ export const makeEffectRequestResponseFromPubSub = Effect.fn("makeEffectRequestR
|
|||
};
|
||||
const backend = yield* pubsub.createConsumer<TRes>(createOptions);
|
||||
const subscribers = new Map<string, Queue.Queue<TRes>>();
|
||||
const stoppedSignal = yield* Deferred.make<never, MessagingLifecycleError>();
|
||||
const fiber = yield* dispatchResponseLoop(backend, options.responseTopic, subscribers, config).pipe(Effect.forkScoped);
|
||||
let stopped = false;
|
||||
|
||||
const stop = Effect.fn(`RequestResponse.stop:${options.requestTopic}`)(function* () {
|
||||
if (stopped) return;
|
||||
stopped = true;
|
||||
yield* Deferred.fail(
|
||||
stoppedSignal,
|
||||
messagingLifecycleError(`${options.requestTopic}:${options.responseTopic}`, "stop", "RequestResponse stopped"),
|
||||
).pipe(Effect.ignore);
|
||||
yield* Fiber.interrupt(fiber);
|
||||
yield* producer.close;
|
||||
yield* closeConsumerBackend(backend, options.responseTopic, options.subscription);
|
||||
|
|
@ -517,6 +522,7 @@ export const makeEffectRequestResponseFromPubSub = Effect.fn("makeEffectRequestR
|
|||
Effect.gen(function* () {
|
||||
yield* producer.send(id, request);
|
||||
const result = yield* waitForResponse(queue, requestOptions).pipe(
|
||||
Effect.raceFirst(Deferred.await(stoppedSignal)),
|
||||
Effect.timeoutOption(Duration.millis(timeoutMs)),
|
||||
);
|
||||
return yield* O.match(result, {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue