Skip to content

feat: add Server-Sent Events endpoint - #279

Merged
jhayniffy merged 1 commit into
InsurNiffy:mainfrom
code-with-flex:feat/event
Mar 29, 2026
Merged

feat: add Server-Sent Events endpoint#279
jhayniffy merged 1 commit into
InsurNiffy:mainfrom
code-with-flex:feat/event

Conversation

@code-with-flex

Copy link
Copy Markdown
Contributor

Description

Implements a Server-Sent Events endpoint at GET /api/events/claims that pushes real-time claim status updates to connected frontend clients. The internal event bus uses Redis pub/sub so every backend instance participates in fan-out, making this horizontally scalable without a centralised broker process. Connections are tracked in a registry that enforces a configurable max connection limit and drains gracefully on SIGTERM.

Related Issue

Closes #202

Changes Made

  • events/claim-events.service.ts — Manages dedicated Redis subscriber and publisher connections (separate from the shared RedisService pool, as pub/sub mode blocks a connection). Exposes publish() for the indexer to call after each Prisma transaction commits. Handles malformed messages and Redis unavailability silently (fail open) so SSE outages do not affect indexer operation.
  • events/sse-connection.registry.ts — Tracks all active Subject-backed SSE connections. Enforces SSE_MAX_CONNECTIONS (default 500) via a hard limit returning 503. drainAll() completes every subject and is called from ClaimEventsService.onModuleDestroy() to flush in-progress event deliveries before the HTTP server shuts down. Includes inline documentation of backpressure behaviour and max connection guidance.
  • events/events.controller.tsGET /api/events/claims?claimId=<id> using @Sse. Uses OptionalJwtAuthGuard so authenticated wallets get the standard throttle and anonymous clients get the stricter 5 req/min limit. Sets retry: 5000 on every event frame so EventSource clients reconnect within 5 s. Sends 25 s heartbeat comments to survive proxy idle timeouts. No DB transaction is held open during connection lifetime.
  • events/events.module.ts — Wires CacheModule, controller, and providers. Exports ClaimEventsService for injection into IndexerModule.
  • indexer/indexer.service.ts — Injects ClaimEventsService optionally (@Optional()) and calls publish() after each $transaction block resolves for claim-related topics. The transaction commits first; publish is fire-and-forget (void) so a Redis failure never rolls back a committed indexer write.
  • indexer/indexer.module.ts — Adds EventsModule to imports to make ClaimEventsService available.
  • app.module.ts — Adds EventsModule to root imports.
  • events/__tests__/events.integration.spec.ts — Integration tests covering: registry registration/unregister, broadcast selectivity, connection limit enforcement, drainAll, publish Redis delivery, silent failure on Redis down, message routing, and malformed-message resilience. No real Redis required.

Acceptance Criteria

  • Frontend receives a push event within indexer lag + pub/sub latency after a claim status change (typically < 15 s on staging)
  • Disconnected clients reconnect via EventSource retry hint and re-subscribe to receive current state
  • Load test confirms connection count stays within SSE_MAX_CONNECTIONS; 503 returned when limit is exceeded
  • Mocked integration tests pass in CI without real Redis credentials
  • SSE connections hold no open DB transactions
  • Graceful shutdown drains active connections before HTTP server closes

@drips-wave

drips-wave Bot commented Mar 29, 2026

Copy link
Copy Markdown

@code-with-flex Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@jhayniffy
jhayniffy merged commit 55822a8 into InsurNiffy:main Mar 29, 2026
1 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backend — Soroban event subscription: SSE stream for real-time claim updates

2 participants