2026-04-05 21:09:33 -05:00
|
|
|
/**
|
|
|
|
|
* Flow-aware processor that manages dynamic flow instances.
|
|
|
|
|
*
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
* Subscribes to config-push topic and dynamically creates/destroys
|
|
|
|
|
* flow instances based on the configuration received.
|
|
|
|
|
*
|
2026-04-05 21:09:33 -05:00
|
|
|
* Python reference: trustgraph-base/trustgraph/base/flow_processor.py
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { AsyncProcessor, type ProcessorConfig } from "./async-processor.js";
|
|
|
|
|
import type { Spec } from "../spec/types.js";
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
import type { BackendConsumer } from "../backend/types.js";
|
2026-04-05 21:09:33 -05:00
|
|
|
import { Flow, type FlowDefinition } from "./flow.js";
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
import { topics } from "../schema/topics.js";
|
2026-05-12 08:06:58 -05:00
|
|
|
import {
|
|
|
|
|
pubSubError,
|
|
|
|
|
type FlowRuntimeError,
|
|
|
|
|
type ProcessorLifecycleError,
|
|
|
|
|
type PubSubError,
|
|
|
|
|
} from "../errors.js";
|
|
|
|
|
import {
|
|
|
|
|
ConsumerFactory,
|
|
|
|
|
FlowRuntime,
|
|
|
|
|
ProducerFactory,
|
|
|
|
|
RequestResponseFactory,
|
|
|
|
|
makeConsumerFactoryService,
|
|
|
|
|
makeProducerFactoryService,
|
|
|
|
|
makeRequestResponseFactoryService,
|
|
|
|
|
runFlowRuntimeScoped,
|
|
|
|
|
} from "../messaging/runtime.js";
|
|
|
|
|
import { makePubSubService, PubSub } from "../backend/pubsub.js";
|
|
|
|
|
import { loadMessagingRuntimeConfig } from "../runtime/messaging-config.js";
|
|
|
|
|
import { Duration, Effect, Exit, Scope } from "effect";
|
|
|
|
|
import * as S from "effect/Schema";
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
|
|
|
|
|
interface ConfigPush {
|
|
|
|
|
version: number;
|
|
|
|
|
config: Record<string, unknown>;
|
|
|
|
|
}
|
2026-04-05 21:09:33 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
interface ActiveFlow {
|
|
|
|
|
readonly scope: Scope.Closeable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ConfigPushSchema = S.Struct({
|
|
|
|
|
version: S.Number,
|
|
|
|
|
config: S.Record(S.String, S.Unknown),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export abstract class FlowProcessor<FlowRequirements = never> extends AsyncProcessor<
|
|
|
|
|
PubSubError | FlowRuntimeError | ProcessorLifecycleError,
|
|
|
|
|
| PubSub
|
|
|
|
|
| FlowRuntime
|
|
|
|
|
| ProducerFactory
|
|
|
|
|
| ConsumerFactory
|
|
|
|
|
| RequestResponseFactory
|
|
|
|
|
| Scope.Scope
|
|
|
|
|
| FlowRequirements
|
|
|
|
|
> {
|
|
|
|
|
private specifications: Array<Spec<FlowRequirements>> = [];
|
|
|
|
|
private flows = new Map<string, ActiveFlow>();
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
private configConsumer: BackendConsumer<ConfigPush> | null = null;
|
2026-04-10 05:45:46 -05:00
|
|
|
private lastFlowsJson = "";
|
2026-04-05 21:09:33 -05:00
|
|
|
|
2026-04-06 21:52:00 -05:00
|
|
|
protected constructor(config: ProcessorConfig) {
|
2026-04-05 21:09:33 -05:00
|
|
|
super(config);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
registerSpecification<Requirements extends FlowRequirements>(
|
|
|
|
|
spec: Spec<Requirements>,
|
|
|
|
|
): void {
|
|
|
|
|
this.specifications.push(spec as Spec<FlowRequirements>);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override async start(): Promise<void> {
|
|
|
|
|
const pubsub = makePubSubService(this.pubsub);
|
|
|
|
|
const messagingConfig = await Effect.runPromise(loadMessagingRuntimeConfig());
|
|
|
|
|
const start = this.startEffect().pipe(
|
|
|
|
|
Effect.provideService(PubSub, pubsub),
|
|
|
|
|
Effect.provideService(ProducerFactory, ProducerFactory.of(makeProducerFactoryService(pubsub))),
|
|
|
|
|
Effect.provideService(ConsumerFactory, ConsumerFactory.of(makeConsumerFactoryService(pubsub, messagingConfig))),
|
|
|
|
|
Effect.provideService(
|
|
|
|
|
RequestResponseFactory,
|
|
|
|
|
RequestResponseFactory.of(makeRequestResponseFactoryService(pubsub, messagingConfig)),
|
|
|
|
|
),
|
|
|
|
|
Effect.provideService(FlowRuntime, FlowRuntime.of({ run: runFlowRuntimeScoped })),
|
|
|
|
|
) as Effect.Effect<void, PubSubError | FlowRuntimeError | ProcessorLifecycleError>;
|
|
|
|
|
await Effect.runPromise(
|
|
|
|
|
Effect.scoped(
|
|
|
|
|
start,
|
|
|
|
|
),
|
|
|
|
|
);
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
protected override runEffect(): Effect.Effect<
|
|
|
|
|
void,
|
|
|
|
|
PubSubError | FlowRuntimeError | ProcessorLifecycleError,
|
|
|
|
|
| PubSub
|
|
|
|
|
| FlowRuntime
|
|
|
|
|
| ProducerFactory
|
|
|
|
|
| ConsumerFactory
|
|
|
|
|
| RequestResponseFactory
|
|
|
|
|
| Scope.Scope
|
|
|
|
|
| FlowRequirements
|
|
|
|
|
> {
|
|
|
|
|
const processor = this;
|
|
|
|
|
return Effect.gen(function* () {
|
|
|
|
|
const pubsub = yield* PubSub;
|
|
|
|
|
|
|
|
|
|
// Subscribe to config-push topic to receive flow definitions.
|
|
|
|
|
// Use "earliest" to replay any config pushes that arrived before this service started.
|
|
|
|
|
processor.configConsumer = yield* pubsub.createConsumer<ConfigPush>({
|
|
|
|
|
topic: topics.configPush,
|
|
|
|
|
subscription: `${processor.config.id}-config-push`,
|
|
|
|
|
initialPosition: "earliest",
|
|
|
|
|
schema: ConfigPushSchema,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
yield* Effect.addFinalizer(() =>
|
|
|
|
|
processor.closeConfigConsumerEffect().pipe(
|
|
|
|
|
Effect.flatMap(() => processor.closeAllFlowsEffect()),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
yield* Effect.log(`[${processor.config.id}] Listening for config pushes on ${topics.configPush}`);
|
|
|
|
|
|
|
|
|
|
yield* Effect.whileLoop({
|
|
|
|
|
while: () => processor.running,
|
|
|
|
|
body: () => processor.processNextConfigPushEffect(),
|
|
|
|
|
step: () => undefined,
|
|
|
|
|
});
|
2026-04-05 21:09:33 -05:00
|
|
|
});
|
2026-05-12 08:06:58 -05:00
|
|
|
}
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
private onConfigureFlowsEffect(
|
|
|
|
|
config: Record<string, unknown>,
|
|
|
|
|
_version: number,
|
|
|
|
|
): Effect.Effect<
|
|
|
|
|
void,
|
|
|
|
|
FlowRuntimeError,
|
|
|
|
|
FlowRuntime | ProducerFactory | ConsumerFactory | RequestResponseFactory | FlowRequirements
|
|
|
|
|
> {
|
|
|
|
|
const processor = this;
|
|
|
|
|
return Effect.gen(function* () {
|
|
|
|
|
const flowDefs = config.flows as Record<string, FlowDefinition> | undefined;
|
|
|
|
|
if (flowDefs === undefined) {
|
|
|
|
|
yield* Effect.log(`[${processor.config.id}] No flows in config push, skipping`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
// Skip flow restart if the flow definitions haven't changed.
|
|
|
|
|
// This prevents disrupting in-flight requests when non-flow config
|
|
|
|
|
// sections (prompts, tools, mcp) are updated.
|
|
|
|
|
const flowsJson = yield* S.encodeUnknownEffect(S.UnknownFromJsonString)(flowDefs).pipe(
|
|
|
|
|
Effect.catch((error) => Effect.succeed(String(error))),
|
|
|
|
|
);
|
|
|
|
|
if (processor.lastFlowsJson.length > 0 && flowsJson === processor.lastFlowsJson && processor.flows.size > 0) {
|
|
|
|
|
yield* Effect.log(`[${processor.config.id}] Flow definitions unchanged, skipping restart`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
processor.lastFlowsJson = flowsJson;
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
// Stop removed flows
|
|
|
|
|
for (const [name, activeFlow] of processor.flows) {
|
|
|
|
|
if (!(name in flowDefs)) {
|
|
|
|
|
yield* Effect.log(`[${processor.config.id}] Stopping removed flow: ${name}`);
|
|
|
|
|
yield* processor.closeFlowEffect(name, activeFlow);
|
|
|
|
|
processor.flows.delete(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
// Start or update flows
|
|
|
|
|
for (const [name, defn] of Object.entries(flowDefs)) {
|
|
|
|
|
// Skip invalid definitions (e.g., stringified JSON)
|
|
|
|
|
if (typeof defn !== "object" || defn === null) {
|
|
|
|
|
yield* Effect.logWarning(`[${processor.config.id}] Skipping flow "${name}": definition is not an object`);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
// Stop existing flow before (re)starting with new config
|
|
|
|
|
const existing = processor.flows.get(name);
|
|
|
|
|
if (existing !== undefined) {
|
|
|
|
|
yield* Effect.log(`[${processor.config.id}] Restarting flow "${name}" with updated config`);
|
|
|
|
|
yield* processor.closeFlowEffect(name, existing);
|
|
|
|
|
processor.flows.delete(name);
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
}
|
|
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
yield* Effect.log(`[${processor.config.id}] Starting flow "${name}"`);
|
|
|
|
|
const activeFlow = yield* processor.startFlowEffect(name, defn);
|
|
|
|
|
processor.flows.set(name, activeFlow);
|
|
|
|
|
yield* Effect.log(`[${processor.config.id}] Flow "${name}" started`);
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
}
|
2026-05-12 08:06:58 -05:00
|
|
|
});
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
override stopEffect(): Effect.Effect<void, ProcessorLifecycleError> {
|
|
|
|
|
return this.closeConfigConsumerEffect().pipe(
|
|
|
|
|
Effect.flatMap(() => this.closeAllFlowsEffect()),
|
|
|
|
|
Effect.flatMap(() => super.stopEffect()),
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-04-05 21:09:33 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
private processNextConfigPushEffect(): Effect.Effect<
|
|
|
|
|
void,
|
|
|
|
|
never,
|
|
|
|
|
FlowRuntime | ProducerFactory | ConsumerFactory | RequestResponseFactory | FlowRequirements
|
|
|
|
|
> {
|
|
|
|
|
const processor = this;
|
|
|
|
|
return Effect.gen(function* () {
|
|
|
|
|
const consumer = processor.configConsumer;
|
|
|
|
|
if (consumer === null) {
|
|
|
|
|
yield* Effect.sleep(Duration.millis(1000));
|
|
|
|
|
return;
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
const msg = yield* Effect.tryPromise({
|
|
|
|
|
try: () => consumer.receive(2000),
|
|
|
|
|
catch: (error) => pubSubError("receive:config-push", error),
|
|
|
|
|
});
|
|
|
|
|
if (msg === null) {
|
|
|
|
|
return;
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
}
|
|
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
const push = msg.value();
|
|
|
|
|
yield* Effect.log(`[${processor.config.id}] Received config push version=${push.version}`);
|
|
|
|
|
|
|
|
|
|
yield* processor.onConfigureFlowsEffect(push.config, push.version);
|
|
|
|
|
|
|
|
|
|
for (const handler of processor.configHandlers) {
|
|
|
|
|
yield* Effect.tryPromise({
|
|
|
|
|
try: () => handler(push.config, push.version),
|
|
|
|
|
catch: (error) => pubSubError("config-handler", error),
|
|
|
|
|
});
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
2026-04-07 01:53:55 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
yield* Effect.tryPromise({
|
|
|
|
|
try: () => consumer.acknowledge(msg),
|
|
|
|
|
catch: (error) => pubSubError("acknowledge:config-push", error),
|
|
|
|
|
});
|
|
|
|
|
}).pipe(
|
|
|
|
|
Effect.catch((error) => {
|
|
|
|
|
if (!processor.running) {
|
|
|
|
|
return Effect.void;
|
|
|
|
|
}
|
|
|
|
|
return Effect.logError(`[${processor.config.id}] Config consumer error`, {
|
|
|
|
|
error: error.message,
|
|
|
|
|
}).pipe(
|
|
|
|
|
Effect.flatMap(() => Effect.sleep(Duration.millis(1000))),
|
|
|
|
|
);
|
|
|
|
|
}),
|
|
|
|
|
);
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
private startFlowEffect(
|
|
|
|
|
name: string,
|
|
|
|
|
definition: FlowDefinition,
|
|
|
|
|
): Effect.Effect<
|
|
|
|
|
ActiveFlow,
|
|
|
|
|
FlowRuntimeError,
|
|
|
|
|
FlowRuntime | ProducerFactory | ConsumerFactory | RequestResponseFactory | FlowRequirements
|
|
|
|
|
> {
|
|
|
|
|
const processor = this;
|
|
|
|
|
return Effect.gen(function* () {
|
|
|
|
|
const flowRuntime = yield* FlowRuntime;
|
|
|
|
|
const scope = yield* Scope.make();
|
|
|
|
|
const flow = new Flow<FlowRequirements>(
|
|
|
|
|
name,
|
|
|
|
|
processor.config.id,
|
|
|
|
|
processor.pubsub,
|
|
|
|
|
definition,
|
|
|
|
|
processor.specifications,
|
|
|
|
|
);
|
|
|
|
|
return yield* flowRuntime.run(flow).pipe(
|
|
|
|
|
Scope.provide(scope),
|
|
|
|
|
Effect.as({ scope } satisfies ActiveFlow),
|
|
|
|
|
Effect.catch((error) =>
|
|
|
|
|
Scope.close(scope, Exit.void).pipe(
|
|
|
|
|
Effect.flatMap(() => Effect.fail(error)),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private closeFlowEffect(name: string, activeFlow: ActiveFlow): Effect.Effect<void> {
|
|
|
|
|
return Scope.close(activeFlow.scope, Exit.void).pipe(
|
|
|
|
|
Effect.tap(() => Effect.log(`[${this.config.id}] Flow "${name}" stopped`)),
|
|
|
|
|
);
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
private closeAllFlowsEffect(): Effect.Effect<void> {
|
|
|
|
|
const processor = this;
|
|
|
|
|
return Effect.gen(function* () {
|
|
|
|
|
const flows = Array.from(processor.flows.entries());
|
|
|
|
|
for (const [name, activeFlow] of flows) {
|
|
|
|
|
yield* processor.closeFlowEffect(name, activeFlow);
|
|
|
|
|
}
|
|
|
|
|
processor.flows.clear();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private closeConfigConsumerEffect(): Effect.Effect<void> {
|
|
|
|
|
const consumer = this.configConsumer;
|
|
|
|
|
this.configConsumer = null;
|
|
|
|
|
if (consumer === null) {
|
|
|
|
|
return Effect.void;
|
|
|
|
|
}
|
|
|
|
|
return Effect.tryPromise({
|
|
|
|
|
try: () => consumer.close(),
|
|
|
|
|
catch: (error) => pubSubError("close:config-push", error),
|
|
|
|
|
}).pipe(
|
|
|
|
|
Effect.catch((error) =>
|
|
|
|
|
Effect.logError(`[${this.config.id}] Failed to close config consumer`, {
|
|
|
|
|
error: error.message,
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
fix: NATS pipeline bugs, add integration tests and service runners
Fix three critical bugs preventing the NATS message pipeline from working:
- FlowProcessor now subscribes to config-push topic (was missing entirely),
using DeliverPolicy.All to replay config on service restart
- NATS streams use wildcard subjects (tg.flow.>) instead of per-topic
narrow filters that caused 503 errors on publish
- Subscriber dispatch loop has exponential backoff on errors to prevent
tight error loops
Add service runner scripts (gateway, config, LLM) and a 7-test
integration suite that verifies config CRUD, WebSocket round-trip,
and full LLM text-completion through the NATS pipeline.
Fix Docker Compose infra: pin Tempo to v2.6.1, remove deprecated Loki
config fields, add user:0 for volume permissions, remap conflicting
ports (FalkorDB 6380, OTLP 4327/4328).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:41:39 -05:00
|
|
|
}
|