feat(iios): wire projectors + relay into DLQ (P9 chaos-safe)
Projectors register a replay handler and route bus errors to dlq.onConsumerFailure (dead-letter + clear the claim-then-fail claim) instead of swallowing them. Relay dead-letters an outbox event after IIOS_OUTBOX_MAX_ATTEMPTS instead of retrying forever. Chaos test proves poison → DLQ → replay resolves while sibling events keep flowing (KG-13/KG-06). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { DlqService } from '../outbox/dlq.service';
|
||||
import { resetDb } from '../test-utils/reset-db';
|
||||
import { makeFakePorts } from '@insignia/iios-testkit';
|
||||
import { IIOS_EVENTS, type CloudEvent } from '@insignia/iios-contracts';
|
||||
@@ -23,7 +24,7 @@ const SECRET = 'dev-adapter-secret'; // AdapterRegistry default
|
||||
const registry = () => new AdapterRegistry();
|
||||
const inbound = () => new InboundService(asService, registry());
|
||||
const projector = () =>
|
||||
new RawEventProjector(asService, new OutboxBus(), registry(), new IngestService(asService, makeFakePorts(), new ActorResolver(asService)));
|
||||
new RawEventProjector(asService, new OutboxBus(), new DlqService(asService), registry(), new IngestService(asService, makeFakePorts(), new ActorResolver(asService)));
|
||||
|
||||
async function rawReceivedEvents(): Promise<CloudEvent[]> {
|
||||
const rows = await prisma.iiosOutboxEvent.findMany({ where: { eventType: IIOS_EVENTS.rawReceived }, orderBy: { createdAt: 'asc' } });
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import { CloudEvent, IIOS_EVENTS } from '@insignia/iios-contracts';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { OutboxBus } from '../outbox/outbox.bus';
|
||||
import { DlqService } from '../outbox/dlq.service';
|
||||
import { AdapterRegistry } from './adapter.registry';
|
||||
import { IngestService } from '../interactions/ingest.service';
|
||||
|
||||
@@ -17,12 +18,14 @@ export class RawEventProjector implements OnModuleInit {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly bus: OutboxBus,
|
||||
private readonly dlq: DlqService,
|
||||
private readonly registry: AdapterRegistry,
|
||||
private readonly ingest: IngestService,
|
||||
) {}
|
||||
|
||||
onModuleInit(): void {
|
||||
this.bus.on(IIOS_EVENTS.rawReceived, (p) => void this.onRawReceived(p as CloudEvent).catch(() => {}));
|
||||
this.dlq.registerHandler(this.consumer, (e) => this.onRawReceived(e));
|
||||
this.bus.on(IIOS_EVENTS.rawReceived, (p) => void this.onRawReceived(p as CloudEvent).catch((err) => this.dlq.onConsumerFailure(this.consumer, p as CloudEvent, err)));
|
||||
}
|
||||
|
||||
async onRawReceived(event: CloudEvent): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user