58 lines
2.4 KiB
Markdown
58 lines
2.4 KiB
Markdown
---
|
|
name: sse_handler
|
|
kind: function
|
|
lang: go
|
|
domain: infra
|
|
version: "1.0.0"
|
|
purity: impure
|
|
signature: "func SSEHandler(events <-chan SSEEvent) http.HandlerFunc"
|
|
description: "Retorna un http.HandlerFunc que setea los headers SSE (Content-Type, Cache-Control, Connection, X-Accel-Buffering), consume eventos del canal y los envia con flush a cada cliente conectado. Cierra limpiamente si el cliente se desconecta (context cancelado) o si el canal de eventos se cierra."
|
|
tags: [sse, server-sent-events, http, handler, server, infra, realtime]
|
|
uses_functions: [sse_send_go_infra]
|
|
uses_types: [SSEEvent_go_infra]
|
|
returns: []
|
|
returns_optional: false
|
|
error_type: "error_go_core"
|
|
imports: [net/http]
|
|
params:
|
|
- name: events
|
|
desc: "canal de SSEEvent del que se consumen eventos para enviar al cliente. Cerrar el canal termina el handler limpiamente."
|
|
output: "http.HandlerFunc lista para montarse en una ruta. Sirve un solo cliente por invocacion (cada request abre su propio stream)."
|
|
tested: true
|
|
tests: ["setea headers SSE correctos", "envia eventos del canal al writer", "termina si el contexto del request se cancela", "termina si el canal de eventos se cierra"]
|
|
test_file_path: "functions/infra/sse_test.go"
|
|
file_path: "functions/infra/sse_handler.go"
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```go
|
|
events := make(chan SSEEvent, 100)
|
|
|
|
routes := []Route{
|
|
{Method: "GET", Path: "/events", Handler: SSEHandler(events)},
|
|
}
|
|
|
|
go func() {
|
|
for i := 0; ; i++ {
|
|
events <- SSEEvent{
|
|
Event: "tick",
|
|
ID: fmt.Sprintf("%d", i),
|
|
Data: fmt.Sprintf(`{"n":%d}`, i),
|
|
}
|
|
time.Sleep(time.Second)
|
|
}
|
|
}()
|
|
|
|
mux := HTTPRouter(routes)
|
|
HTTPServe(":8080", mux, ctx)
|
|
```
|
|
|
|
## Notas
|
|
|
|
Importante: este handler asume **un canal compartido entre todos los clientes** o un canal por request. Si se quiere broadcast a multiples clientes desde una sola fuente, montar un fan-out por encima (ej: un hub similar a `WSHub` pero para SSE). Para uso tipico (1 cliente = 1 stream) basta con crear el canal dentro del handler externo y pasarlo.
|
|
|
|
`X-Accel-Buffering: no` deshabilita el buffering en nginx (sin esto los eventos se acumulan hasta que nginx flushea su buffer, anulando el real-time). En Caddy/Traefik no es necesario pero no estorba.
|
|
|
|
El handler **no monta keepalives** automaticamente. Si la conexion va a estar idle mas de ~30s, lanzar `SSEKeepalive` en una goroutine paralela compartiendo el mismo writer.
|