--- 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, pendiente-usar] 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.