---
name: sse_keepalive
kind: function
lang: go
domain: infra
version: "1.0.0"
purity: impure
signature: "func SSEKeepalive(w http.ResponseWriter, interval time.Duration, done <-chan struct{})"
description: "Envia comentarios SSE periodicos (`: keepalive\\n\\n`) al writer hasta que done se cierre. Sirve para evitar que proxies o load balancers cierren conexiones inactivas. Bloqueante: lanzar como goroutine. Si w implementa http.Flusher hace flush tras cada keepalive."
tags: [sse, keepalive, server-sent-events, http, server, infra, realtime, pendiente-usar]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [net/http, time]
params:
  - name: w
    desc: "http.ResponseWriter destino del stream SSE. Si implementa http.Flusher se hace flush tras cada keepalive."
  - name: interval
    desc: "intervalo entre keepalives (recomendado 15-30s). Si <= 0 se usa 30s por defecto."
  - name: done
    desc: "canal de cierre. Cuando se cierre, la goroutine retorna inmediatamente."
output: "ningun retorno; la funcion retorna cuando done se cierra o cuando una escritura falla (cliente desconectado)"
tested: true
tests: ["escribe comentario keepalive periodicamente", "termina cuando done se cierra", "termina cuando la escritura falla"]
test_file_path: "functions/infra/sse_test.go"
file_path: "functions/infra/sse_keepalive.go"
---

## Ejemplo

```go
http.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")

    done := make(chan struct{})
    defer close(done)

    go SSEKeepalive(w, 15*time.Second, done)

    // Bucle principal de envio de eventos...
})
```

## Notas

Comentario SSE: la spec dice que cualquier linea que empiece con `:` es un comentario y el cliente la ignora. Mantienen viva la conexion sin generar eventos espurios. Recomendado intervalo entre 15-30s para infraestructuras tipicas (nginx default = 60s timeout idle).

Si la escritura falla (conexion cerrada) la funcion retorna sin error, asumiendo que el handler principal ya detectara la desconexion via `r.Context().Done()`.
