Skip to content

[ENG-36796] feat: add real-time server-sent events infrastructure (SSE)#3349

Open
gdsantana wants to merge 8 commits intodevfrom
ENG-36794
Open

[ENG-36796] feat: add real-time server-sent events infrastructure (SSE)#3349
gdsantana wants to merge 8 commits intodevfrom
ENG-36794

Conversation

@gdsantana
Copy link
Contributor

@gdsantana gdsantana commented Mar 5, 2026

Jira Tasks

  • ENG-36794 Implementar conexão Server-Sent Events (SSE) no Console
  • ENG-36795 Implementar o processamento de mensagens SSE recebidas pelo Console
  • ENG-36796 Integrar eventos activity recebidos via SSE com o mecanismo de cache do TanStack Query

Description

Adds a complete Server-Sent Events (SSE) infrastructure for handling real-time updates and activity notifications in the Console.

ENG-36794: SSE Connection Implementation

Implements a real-time SSE connection with the endpoint:

GET /events/stream

Headers:

Authorization: Token <token>
Accept: text/event-stream

Connection Event:

event: message
data: {"type": "connected", "client_id": "9999z", "timestamp": "2026-03-03T19:58:10.690698Z"}

Requirements Implemented:

  • Open SSE connection after user authentication
  • Use current session token
  • Automatic reconnection if connection is lost
  • Maintain only one active connection per session

ENG-36795: SSE Message Processing

Implements parsing and processing of SSE messages received by the Console.

Activity Event Payload:

{
  "type": "activity",
  "data": {
    "user": {
      "email": "user@example.com",
      "name": "User Name"
    },
    "activity_type": "created | edited | deleted",
    "resource": {
      "type": "edge_application",
      "name": "Application Name",
      "id": null
    },
    "timestamp": "2026-03-03T19:58:56Z",
    "description": "Application Name was created",
    "metadata": {
      "id": 1772562194,
      "name": "Application Name",
      "last_editor": "user@example.com",
      "last_modified": "2026-03-03T19:58:55.548847Z",
      ...
    }
  }
}

Processing Capabilities:

  • Parse event.data from received messages
  • Identify events of type activity
  • Extract relevant information for cache invalidation:
    • data.resource.type - resource type
    • data.activity_type - action type
    • data.metadata.id - resource identifier

ENG-36796: TanStack Query Cache Integration

Integra eventos activity recebidos via SSE com o mecanismo de cache do TanStack Query, permitindo que o Console atualize automaticamente os dados exibidos.

A invalidação deve ocorrer com base nas informações do payload.

Campos utilizados:

  • data.resource.type
  • data.activity_type
  • data.metadata.id

Regras de invalidação:

// Sempre invalidar a lista do recurso:
queryClient.invalidateQueries([resource.type])

// Quando existir identificador do recurso:
queryClient.invalidateQueries([resource.type, metadata.id])

Isso garante atualização automática de:

  • Listas de recursos
  • Páginas de detalhe

Smart Cache Invalidation

Parent-Based Resolution Strategy

Implements intelligent cache invalidation that resolves Vue Query keys from SSE activity events using structured fields (resource.type, parent.type, parent.id). This enables targeted cache invalidation for nested resources.

Invalidation Priority:

  1. Parent-based - Invalidates using parent.type + parent.id (most specific)
  2. Resource-based - Invalidates using resource.type + metadata.id
  3. Description fallback - Extracts resource type from description text

Key Features:

  • getKeysForResource() - Maps resource types to query keys
  • getParentKeys() - Resolves parent-based cache keys for nested resources
  • Factory functions for mapping configurations (simple, detail, multi-key)
  • Expanded PARENT_TYPE_TO_QUERY_KEY mapping for 30+ parent resource types
  • Ping event handler to maintain SSE connection alive

Example Flow:

SSE Event: rule_engine created under edge_application 12345
         ↓
Resolution: parent.type="edge_application", parent.id=12345
         ↓
Invalidation: queryClient.invalidateQueries(['edge-application', 12345])
         ↓
Result: Cache refreshed for parent + all nested queries

Supported Parent Types:

Parent Type Query Key Pattern
edge_application ['edge-application', id]
edge_function ['edge-function', id]
database ['database', id]
domain ['domain', id]
... (30+ types supported)

Components Added

Component Path Description
SSEClient src/services/v2/base/sse/sse-client.js Wrapper with automatic reconnection and event parsing
SSEService src/services/v2/base/sse/sse-service.js Singleton managing global state, cross-tab coordination, and cache invalidation
useSSE composable src/composables/useSSE.js Vue composable for easy component integration
Session integration src/services/v2/base/auth/sessionManager.js Starts/stops SSE based on auth state
Unit tests src/tests/services/v2/base/sse/sse-client.test.js Comprehensive test coverage for the client
Vite proxy config vite.config.js Proxy configuration for /events/stream endpoint

Acceptance Criteria

ENG-36794

  • Upon logging into the Console, an SSE connection is opened
  • The connected event is received after connection
  • If the connection is interrupted, it is automatically re-established
  • No multiple simultaneous SSE connections exist

ENG-36795

  • Received activity events are correctly parsed
  • Affected resource data is identified
  • System can identify:
    • Resource type (resource.type)
    • Action type (activity_type)
    • Resource identifier (metadata.id)

ENG-36796

  • Evento created invalida queries do recurso
  • Evento edited invalida queries do recurso
  • Evento deleted invalida queries do recurso
  • TanStack Query executa refetch automaticamente
  • UI reflete as alterações sem refresh manual

Definition of Done

ENG-36794

  • Code implemented and reviewed
  • Functional SSE connection in development environment
  • Automatic reconnection tested
  • Error logs handled

ENG-36795

  • Event parser implemented
  • Payload processed without field loss
  • Error logs implemented for invalid payload

ENG-36796

  • Integração com queryClient implementada
  • Invalidação de queries funcionando
  • Atualização automática validada em ambiente de desenvolvimento

Technical Details

  • Automatic reconnection: Exponential backoff with configurable max delay
  • Cross-tab coordination: Uses BroadcastChannel for multi-tab sync
  • Cache invalidation: Triggers Vue Query cache updates on relevant events
  • Session lifecycle: SSE starts on login, stops on logout

How to Test

  1. Start the dev server: yarn dev
  2. Login to the application
  3. Open browser DevTools → Network tab
  4. Filter for "EventStream" type requests
  5. Verify that a connection to /events/stream is established
  6. Verify the connected event is received with client_id
  7. Test reconnection by temporarily disconnecting network
  8. Verify SSE automatically reconnects when network returns
  9. Verify no duplicate connections exist (check Network tab)
  10. Run tests: yarn test:unit:headless --run src/tests/services/v2/base/sse/sse-client.test.js

Adds a complete Server-Sent Events (SSE) infrastructure for handling real-time updates and activity notifications.

Includes:
- SSEClient wrapper with automatic reconnection and event parsing
- Singleton SSEService managing global state, cross-tab coordination, and cache invalidation
- Vue composable useSSE for easy component integration
- Session lifecycle integration to start/stop SSE based on auth state
- Comprehensive unit tests for the client
- Proxy configuration for the /events/stream endpoint
HerbertJulio and others added 6 commits March 5, 2026 16:04
Remove duplicated BroadcastManager/TabCoordinator instances by
merging SSEService into CacheSyncService. Extract CacheInvalidator
for SRP. Fix proxy rewrite, duplicate listener, and sort bugs.
- only start SSE for client accounts (account.kind === 'client')
- wire afterLogin into accountGuard to trigger SSE after session load
- close existing EventSource before creating new connection
- add 60s inactivity watchdog to detect silent connection deaths
- add console.log for cache invalidation debugging
Remove client-side inactivity timeout mechanism from SSE client and
implement reconnection logic in cache-sync-service when server closes
the connection. This provides more reliable handling of server-initiated
disconnects by responding to explicit close events rather than relying
on inactivity detection.

- Add scheduleReconnect and clearClosedReconnectTimeout methods
- Remove inactivityTimeout option and related methods from SSE client
- Add tests for ping and closed event handling
Update invalidate method to extract and validate structured fields
(resourceType, activityType, resourceId) from SSE activity events.
Add validation logging for missing required fields and improve log
output with structured event information.
…ution

Add parent-based cache invalidation that resolves query keys from SSE activity
events using structured fields (resource.type, parent.type, parent.id). This
enables targeted cache invalidation for nested resources.

Changes:
- Add getKeysForResource and getParentKeys functions for structured invalidation
- Create factory functions for mapping configurations (simple, detail, multi-key)
- Expand PARENT_TYPE_TO_QUERY_KEY mapping for 30+ parent resource types
- Implement invalidation priority: parent-based > resource-based > description fallback
- Add ping event handler to maintain SSE connection
- Update tests for new invalidation strategies
@gdsantana gdsantana changed the title [ENG-36794] feat: add real-time server-sent events infrastructure [ENG-36796] feat: add real-time server-sent events infrastructure Mar 12, 2026
@gdsantana gdsantana changed the title [ENG-36796] feat: add real-time server-sent events infrastructure [ENG-36796] feat: add real-time server-sent events infrastructure (SSE) Mar 12, 2026
Adds a comprehensive guide for the SSE (Server-Sent Events) implementation
used for real-time synchronization and automatic cache invalidation.

Covers core components (SSEClient, CacheSyncService, CacheInvalidator),
multi-tab coordination, invalidation mapping strategies, the useSSE composable,
and testing instructions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acho que subiu sem querer esse arquivo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge enhancement New feature or request

Development

Successfully merging this pull request may close these issues.

2 participants