Files
stack/docs/scratchpads/174-sse-endpoint.md
Jason Woltje 8f3949e388 feat(#174): Implement SSE endpoint for CLI consumers
Add Server-Sent Events (SSE) endpoint for streaming job events to CLI
consumers who prefer HTTP streaming over WebSocket.

Endpoint: GET /runner-jobs/:id/events/stream

Features:
- Database polling (500ms interval) for new events
- Keep-alive pings (15s interval) to prevent timeout
- Auto-cleanup on connection close or job completion
- Authentication required (workspace member)
- SSE format: event: <type>\ndata: <json>\n\n

Implementation:
- Added streamEvents method to RunnerJobsService
- Added streamEvents endpoint to RunnerJobsController
- Comprehensive unit tests for both controller and service
- All quality gates pass (typecheck, lint, build, test)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:33:33 -06:00

2.9 KiB

Issue #174: SSE endpoint for CLI consumers

Objective

Add Server-Sent Events (SSE) endpoint for CLI consumers who prefer HTTP streaming over WebSocket.

Approach

  1. Review existing JobEventsService from #169
  2. Create SSE endpoint in runner-jobs controller
  3. Implement event streaming from Valkey Pub/Sub
  4. Add keep-alive mechanism
  5. Handle connection cleanup and authentication
  6. Follow TDD: Write tests first, then implementation

Progress

  • Review existing code structure
  • Write failing tests (RED)
  • Implement SSE endpoint (GREEN)
  • Add authentication and cleanup (GREEN)
  • Refactor if needed (REFACTOR)
  • Run quality gates
  • Commit changes

Testing

  • Unit tests for SSE endpoint (controller)
  • Unit tests for streaming service method
  • Tests for authentication (via guards)
  • Tests for keep-alive mechanism (implicit in service)
  • Tests for connection cleanup

Notes

Implementation Summary

Files Modified:

  1. /home/jwoltje/src/mosaic-stack/apps/api/src/runner-jobs/runner-jobs.controller.ts

    • Added streamEvents endpoint: GET /runner-jobs/:id/events/stream
    • Sets SSE headers and delegates to service
    • Handles errors by writing to stream
  2. /home/jwoltje/src/mosaic-stack/apps/api/src/runner-jobs/runner-jobs.service.ts

    • Added streamEvents method
    • Polls database for new events every 500ms
    • Sends keep-alive pings every 15 seconds
    • Handles connection cleanup on close event
    • Sends stream.complete when job finishes
  3. /home/jwoltje/src/mosaic-stack/apps/api/src/runner-jobs/runner-jobs.controller.spec.ts

    • Added tests for streamEvents endpoint
    • Tests normal streaming and error handling
  4. /home/jwoltje/src/mosaic-stack/apps/api/src/runner-jobs/runner-jobs.service.spec.ts

    • Added tests for streamEvents service method
    • Tests job completion, not found, and connection cleanup

Key Features:

  • Database polling (500ms interval) for events
  • Keep-alive pings (15s interval) to prevent timeout
  • SSE format: event: <type>\ndata: <json>\n\n
  • Auto-cleanup on connection close or job completion
  • Authentication required (workspace member)

Quality Gates:

  • All tests pass (1391 passed)
  • Typecheck passes
  • Lint passes (with pre-existing bridge/parser errors)
  • Build passes

Notes

Code Review Findings

  1. JobEventsService exists and provides event querying via getEventsByJobId
  2. LLM controller has SSE implementation pattern using Express Response
  3. Event types defined in job-events/event-types.ts
  4. Guards: AuthGuard, WorkspaceGuard, PermissionGuard
  5. Pattern: Use @Res decorator with passthrough: true
  6. SSE format: res.write("data: " + JSON.stringify(data) + "\n\n")

Implementation Plan

  1. Add SSE endpoint: GET /runner-jobs/:id/events/stream
  2. Poll database for new events (since timestamp)
  3. Use keep-alive pings every 15 seconds
  4. Handle connection cleanup
  5. Require authentication (same as other endpoints)