Skip to main content

Push flag changes instantly via SSE or gRPC streaming — connection lifecycle, reconnection, and scaling

Real-Time Updates

Flaggr supports two real-time update mechanisms for pushing flag changes to connected clients without polling.

SSE (Server-Sent Events)

The default real-time protocol for browser clients. Uses the standard EventSource API.

GET /api/connect/stream?serviceId=web-app&environment=production&clientId=client-1
Client ID

Each client should provide a unique clientId for connection tracking and deduplication.

Query parameters:

ParameterRequiredDescription
serviceIdYesService to subscribe to
environmentYesdevelopment, staging, or production
clientIdYesUnique client identifier
flagKeyNoSubscribe to specific flags (repeatable)

Event Format

Events arrive as JSON payloads:

{
  "eventType": "UPDATED",
  "flagKey": "checkout-v2",
  "flag": {
    "key": "checkout-v2",
    "enabled": true,
    "defaultValue": true
  },
  "timestamp": "2025-07-20T10:30:00Z",
  "configVersion": "v42"
}

Event types:

TypeDescription
PROVIDER_READYInitial connection established, current config sent
CREATEDNew flag created
UPDATEDExisting flag configuration changed
DELETEDFlag removed
SYNCFull configuration sync
HEARTBEATKeep-alive (every 30 seconds)

Browser Usage

const eventSource = new EventSource(
  '/api/connect/stream?serviceId=web-app&environment=production&clientId=browser-1'
)
 
eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data)
 
  if (data.eventType === 'UPDATED') {
    console.log(`Flag ${data.flagKey} changed`)
    // Update local flag cache
  }
}
 
eventSource.onerror = () => {
  console.log('Connection lost, EventSource will auto-reconnect')
}
Auto-Reconnection

The browser's EventSource API automatically reconnects on connection loss with exponential backoff. You don't need to implement reconnection logic.

SDK Integration

The web provider handles SSE internally:

const provider = new FlaggrWebProvider({
  apiUrl: 'https://flaggr.dev',
  serviceId: 'web-app',
  enableStreaming: true, // Enables SSE
})
 
// Flag changes are applied automatically
// Hook consumers re-render when values change

gRPC Streaming

Server-side streaming for high-throughput environments. Provides bidirectional communication with lower overhead than SSE.

Connection Setup

import { GrpcProvider } from '@flaggr/client'
 
const provider = new GrpcProvider({
  grpcAddress: 'flaggr.dev:50051',
  serviceId: 'payment-service',
  environment: 'production',
  apiToken: 'flg_your_token',
  flagKeys: ['checkout-v2', 'dark-mode'], // Subscribe to specific flags
})

Streaming Lifecycle

Client                          Server
  │                               │
  ├── StreamFlags(request) ──────►│
  │                               │
  │◄── PROVIDER_READY (full config)│
  │                               │
  │        ... time passes ...    │
  │                               │
  │◄── UPDATED (flag changed) ───│
  │◄── CREATED (new flag) ───────│
  │                               │
  │        ... heartbeat ...      │
  │◄── HEARTBEAT ────────────────│
  │                               │

Reconnection

The gRPC provider includes automatic reconnection with configurable backoff:

const provider = new GrpcProvider({
  grpcAddress: 'flaggr.dev:50051',
  serviceId: 'my-service',
  reconnect: {
    enabled: true,
    maxAttempts: 10,
    initialDelayMs: 1000,  // Start at 1s
    maxDelayMs: 30000,     // Cap at 30s
  },
})

Delivery Architecture

Primary: Redis Pub/Sub

When Redis is configured, flag changes are published to a Redis channel. All SSE and gRPC stream handlers subscribe to this channel for instant delivery.

Flag Update → Redis PUBLISH → All Stream Handlers → Connected Clients

Fallback: Polling

When Redis is unavailable, the stream handlers fall back to polling the database every 5 seconds. This is transparent to clients.

Scaling Note

Without Redis, in-memory broadcast only reaches clients connected to the same instance. For multi-instance deployments, Redis is required for cross-instance flag change delivery.

Protocol Comparison

FeatureSSEgRPC Streaming
Browser supportNativeVia gRPC-Web
Server supportNoYes
BidirectionalNoYes
Auto-reconnectBrowser-nativeCustom logic
OverheadHTTP/1.1HTTP/2 binary
Connection limit6 per domainUnlimited
Best forSPAs, dashboardsMicroservices

Connection Monitoring

Track connection state in your application:

provider.onConnectionStateChange((state) => {
  // CONNECTING → CONNECTED → DISCONNECTED → ERROR
  console.log('Connection state:', state)
 
  if (state === 'ERROR') {
    // Show fallback UI or use cached values
  }
})

The useConnectionState() React hook provides this in components:

function StatusBadge() {
  const state = useConnectionState()
  return state === 'CONNECTED'
    ? <span className="text-green-500">Live</span>
    : <span className="text-yellow-500">Reconnecting...</span>
}

Metrics

Real-time connections are tracked via Prometheus:

MetricDescription
flaggr_grpc_active_connectionsActive gRPC streaming connections
flaggr_grpc_active_streamsActive gRPC streams
flaggr_grpc_messages_totalTotal gRPC messages (by direction)

SSE connections are tracked as active connections with an endpoint label (connect or legacy).