SSE Broadcast

Keep an SSE connection open and broadcast events to all connected clients.

Full source

File: pwsh/tutorial/examples/15.10-SseBroadcast.ps1

<#
    Create a broadcast SSE demo server with Kestrun in PowerShell.
    FileName: 15.10-SseBroadcast.ps1

    This demo shows server-side broadcasting to all connected SSE clients.

    Broadcast SSE pieces:
    - Add-KrSseBroadcastMiddleware (registers broadcaster + maps /sse/broadcast)
    - Send-KrSseBroadcastEvent (broadcasts to all connected clients)

    Per-request SSE helpers (still available):
    - Start-KrSseResponse
    - Write-KrSseEvent
#>
param(
    [int]$Port = 5000,
    [IPAddress]$IPAddress = [IPAddress]::Loopback
)

if (-not (Get-Module Kestrun)) { Import-Module Kestrun }

Initialize-KrRoot -Path $PSScriptRoot

New-KrLogger |
    Set-KrLoggerLevel -Value Debug |
    Add-KrSinkConsole | Register-KrLogger -Name 'SseBroadcastDemo' -SetAsDefault

New-KrServer -Name 'Kestrun SSE Broadcast Demo'

Add-KrEndpoint -Port $Port -IPAddress $IPAddress

 

# Add the broadcast SSE endpoints (implemented in C#; keeps connections open)
# 1) Default broadcast SSE stream (schema defaults to string in OpenAPI)
Add-KrSseBroadcastMiddleware -Path '/sse/broadcast' -KeepAliveSeconds 15

# 2) Progress broadcast SSE stream (OpenAPI payload schema: OperationProgressEvent)
Add-KrSseBroadcastMiddleware -Path '/sse/broadcast/progress' -KeepAliveSeconds 15


Enable-KrConfiguration

# Home page
Add-KrHtmlTemplateRoute -Pattern '/' -HtmlTemplatePath 'Assets/wwwroot/sseBroadcast.html'

# Broadcast API
Add-KrMapRoute -Verbs Post -Pattern '/api/broadcast' {
    try {
        $body = Get-KrRequestBody
        $eventName = [string]($body.event ?? 'message')

        $dataObj = $body.data
        if ($null -eq $dataObj) { $dataObj = @{ text = 'empty' } }

        $dataJson = $dataObj | ConvertTo-Json -Compress

        Send-KrSseBroadcastEvent -Event $eventName -Data $dataJson

        $count = Get-KrSseConnectedClientCount

        Write-KrJsonResponse -InputObject @{ ok = $true; event = $eventName; connected = $count } -StatusCode 200
    } catch {
        Write-KrLog -Level Error -Exception $_.Exception -Message 'Send-KrSseBroadcastEvent failed: {error}' -Values $_.ToString()
        # Generate error response
        $err = [SseBroadcastErrorResponse]::new()
        $err.ok = $false
        $err.error = 'Sse Broadcast failed. See server logs for details.'
        Write-KrJsonResponse -InputObject $err -StatusCode 500
    }
}

# Progress Broadcast API
Add-KrMapRoute -Verbs Post -Pattern '/api/broadcast/progress' {
    try {
        $body = Get-KrRequestBody

        $payload = @{
            taskId = [string]($body.taskId ?? 'task-1')
            progress = [double]($body.progress ?? 0)
            status = [string]($body.status ?? 'Working...')
            state = [string]($body.state ?? 'running')
            ts = (Get-Date).ToUniversalTime()
        }

        $dataJson = $payload | ConvertTo-Json -Compress
        Send-KrSseBroadcastEvent -Event 'progress' -Data $dataJson

        $count = Get-KrSseConnectedClientCount

        Write-KrJsonResponse -InputObject @{ ok = $true; event = 'progress'; connected = $count } -StatusCode 200
    } catch {
        Write-KrLog -Level Error -Exception $_.Exception -Message 'Send-KrSseBroadcastEvent failed: {error}' -Values $_.ToString()
        # Generate error response
        $err = [SseBroadcastErrorResponse]::new()
        $err.ok = $false
        $err.error = 'Sse Broadcast failed. See server logs for details.'
        Write-KrJsonResponse -InputObject $err -StatusCode 500
    }
}

Write-Host '๐ŸŸข Kestrun SSE Broadcast Demo Server Started' -ForegroundColor Green
Write-Host "๐Ÿ“ Navigate to http://localhost:$Port" -ForegroundColor Cyan
Write-Host "๐Ÿ“ก Broadcast SSE endpoint: http://localhost:$Port/sse/broadcast" -ForegroundColor Cyan
Write-Host "๐Ÿ“ˆ Progress SSE endpoint: http://localhost:$Port/sse/broadcast/progress" -ForegroundColor Cyan

Start-KrServer -CloseLogsOnExit

Step-by-step

  1. Logging: Register a console logger as default.
  2. Server: Create a server and listener (IP + port).
  3. Broadcast SSE: Add Add-KrSseBroadcastMiddleware to expose /sse/broadcast.
  4. Configuration: Enable configuration so middleware and routes are active.
  5. Home page: Serve an HTML demo with an EventSource('/sse/broadcast') client.
  6. Broadcast API: Implement POST /api/broadcast to accept { event, data } JSON.
  7. Broadcast: Send events to all clients using Send-KrSseBroadcastEvent.
  8. Run: Start the server, connect clients, then broadcast messages.

Try it

Start the server:

pwsh .\docs\_includes\examples\pwsh\15.10-SseBroadcast.ps1

Open the demo UI and connect:

Start-Process http://127.0.0.1:5000/

Broadcast a message via the API:

curl -i -X POST http://127.0.0.1:5000/api/broadcast \
  -H "Content-Type: application/json" \
  -d "{\"event\":\"message\",\"data\":{\"text\":\"hello\"}}"

Troubleshooting

Symptom Cause Fix
SSE stream never shows events No clients connected Connect a client to /sse/broadcast before broadcasting.
Broadcast API returns 500 Bad JSON body Ensure Content-Type: application/json and send { event, data }.
Browser reconnect loop Connection interrupted Check proxies/load balancers; increase -KeepAliveSeconds to keep intermediaries from timing out.

References


Previous / Next

Previous: SSE Next: Health