SSE Bind Status
Bind is asynchronous. The gateway returns 202 immediately and processes bind in the background. The frontend subscribes to a Server-Sent Events (SSE) stream to receive real-time status updates without polling.
Why SSE
- Bind can take 1–2 minutes (Safeco RC3 API, payment processing)
- Heroku enforces a 30-second HTTP timeout; a synchronous bind request would time out
- SSE provides a long-lived stream that bypasses the timeout while delivering real-time status
Endpoint
GET /api/v1/ghcms/safeco/bind/status/stream?sessionId=<uuid>
Query param sessionId is required (UUID v4). Credentials sent via cookies (withCredentials: true).
Backend
apps/apis/fastlane-api-gateway/src/app/controllers/safeco.controller.ts — bindStatusStream:
- Uses
BindStatusServicefor in-memory status per session - Emits
statusevents:{ status, data?, error?, timestamp } - Sends last known status immediately (if any)
- Merges live status updates from
BindStatusService - Heartbeat every 15 seconds
- Stream ends when status is
SUCCESSorFAILED
BindStatusService (apps/apis/fastlane-api-gateway/src/app/services/bind-status.service.ts):
- RxJS
SubjectpersessionId setStatus(sessionId, status, data?, error?)— called by bind controllergetStatusStream(sessionId)— returns observable of status events- Cleans up 5 minutes after terminal status
Event Payload
{
"status": "PENDING" | "BINDING" | "SUCCESS" | "FAILED",
"data": { "policyNumber": "..." },
"error": "Error message if FAILED",
"timestamp": "2025-03-11T12:00:00.000Z"
}
Frontend Hook
useSafecoBindSSE (apps/fastlane-portal/src/app/hooks/use-safeco-bind-sse.ts):
- Input:
sessionId,listening(true after bind POST succeeds) - Connection:
new EventSource(url, { withCredentials: true }) - Events: Listens for
statusevents - Reconnect: Up to 3 attempts with exponential backoff (1s, 2s, 4s)
- On SUCCESS: Sets
bindData(e.g.policyNumber), closes connection - On FAILED: Sets
bindError, closes connection
Returns: { bindStatus, bindData, bindError, isBinding, reset }
Checkout Integration
checkout.tsx:
useSafecoBindSSE(session?.uuid, sseListening)sseListeningset totrueafter successful bind POST- On
bindStatus === 'SUCCESS': navigate to/carriers/safeco/auto/success BindingPolicyModalshown whileisBindingis true (PENDING or BINDING)