Yeda AI Tips · #113

English

Nunca lances una goroutine sin dueño

La fuga invisible en los servicios Go generados por IA es una goroutine lanzada sin dueño. A los asistentes de IA les encanta la palabra clave go: es una sola palabra, compila y la demo funciona. Pero las goroutines no se recolectan como basura. El artículo de pipelines del propio equipo de Go es directo: las goroutines consumen memoria y recursos del runtime, y las referencias en sus stacks impiden que el recolector libere esos datos; las goroutines no se recolectan — deben terminar por sí mismas. Una goroutine sin señal de cancelación y sin un modelo de workers acotado nunca termina. Se fuga en silencio — unos pocos KB de stack cada una, más todo lo que su stack referencia — hasta que tu servicio se cae.

Por qué el Go generado por IA se fuga

El código generado optimiza para "compila y pasa el camino feliz". El patrón clásico parece inofensivo:

go func() {
    for msg := range ch {
        process(msg)
    }
}()

¿Quién cierra ch? ¿Quién espera a esta goroutine al apagar el servicio? ¿Qué la detiene si la petición del llamador se cancela? Si no puedes responder las tres preguntas leyendo el punto de lanzamiento, tienes una fuga. Bajo carga, los emisores bloqueados se acumulan detrás de un receptor que dejó de leer, y cada uno retiene su mensaje en memoria para siempre.

El contrato de propiedad

Cada goroutine necesita un dueño cuyo ciclo de vida sea visible donde se lanza. Tres mecanismos lo cubren:

PreguntaMecanismoRegla práctica
¿Cómo se detiene?Cancelación con context.ContextPasa ctx; haz select sobre ctx.Done() en cada bucle bloqueante
¿Quién cierra el canal?close del lado emisorSolo la goroutine que envía por un canal lo cierra — nunca el receptor
¿Quién la espera?sync.WaitGroupwg.Add(1) antes de go, defer wg.Done() adentro, wg.Wait() al apagar

Todo junto, una goroutine con dueño se lee así:

wg.Add(1)
go func() {
    defer wg.Done()
    for {
        select {
        case <-ctx.Done():
            return
        case msg, ok := <-ch:
            if !ok {
                return
            }
            process(msg)
        }
    }
}()

La cancelación, la propiedad del canal y la limpieza son evidentes en el punto de lanzamiento — exactamente lo que hace revisable al código generado.

Señales de alarma en una revisión

Trucos avanzados

Recursos

¿Construyes una funcionalidad con IA? Yeda AI diseña, audita y lanza sistemas LLM de producción.

Habla con nosotros · Lee el blog