Control de contexto en Go
Los desarrolladores de Go debaten cómo usar `context` y goroutines de forma responsable, con foco en la cancelación, la vida útil de los recursos y en evitar concurrencia oculta en las bibliotecas. Muchos prefieren APIs que parezcan síncronas y donde los llamadores controlen si el trabajo se ejecuta en paralelo, aunque reconocen casos legítimos para goroutines internas y trabajadores de larga duración. La conversación también critica `context` como una mezcla de cancelación y datos acotados al pedido, lo compara con patrones en Rust y C#, y menciona la concurrencia estructurada y los límites del ideal de Go de “sin coloración async”.
Goroutines en bibliotecas y diseño de API
- Tema fuerte: las APIs de bibliotecas deberían parecer síncronas; los llamadores deciden si quieren concurrencia creando ellos mismos goroutines.
- Las goroutines internas son aceptables cuando:
- Forman claramente parte de la abstracción (por ejemplo, rastreador web, map paralelo, pub/sub por lotes, expulsor de métricas).
- Están acotadas, bien documentadas y son ajustables (límites, tasa, loteo, topes de trabajo en curso).
- Se limpian correctamente antes de que la función pública devuelva el control (estilo de concurrencia estructurada, a menudo mediante
errgroupoWaitGroup).
- Quienes critican “nunca inicies goroutines en bibliotecas” dicen que eso es demasiado rígido; algunas cargas de trabajo son más simples y seguras si la biblioteca se encarga de la planificación.
- Las panics en goroutines en segundo plano son una preocupación: los llamadores no pueden envolverlas en
recovera menos que controlen el límite de la goroutine.
Context: propósito, patrón y puntos de dolor
- Dos roles principales:
- Cancelación / plazos / “ya puedes parar”.
- Datos acotados al pedido (logger, trazado, autenticación, etc.).
- A muchos no les gusta el aspecto de “bolsa de cosas”; es difícil saber por qué una función necesita un context o qué contiene.
- Otros defienden los parámetros explícitos
ctx:- Hacen visibles la interrumpibilidad y los requisitos de registro.
- Son más fáciles de revisar y razonar que el almacenamiento implícito por hilo.
- Guía debatida:
- Regla común: no almacenar contexts; pasarlos hacia abajo en la pila.
- Matiz: está bien en structs que, en la práctica, son parámetros, y en la stdlib por compatibilidad hacia atrás (por ejemplo,
net/http), a veces usandoNewRequestWithContext. context.WithoutCancelse ve como un compromiso útil cuando se almacenan “valores pero no plazos”.
- Puntos de fricción:
- No hay forma estática de saber si los callee respetan el context.
- Presión para propagar
ctxpor “casi todas las funciones”, especialmente para el registro.
Context vs. coloración de funciones / modelos async
- Algunos ven
ctxcomo una ligera “coloración” (funciones con y sin context), socavando en parte la historia de Go de “sin palabra clave async”. - Otros sostienen que es mucho menos restrictivo que async/await:
- Siempre puedes usar
context.Background()o envolverlo con timeouts. - No crea la separación dura entre sync y async que se ve en otros lenguajes.
- Siempre puedes usar
Manejo de errores y valores cero (tema lateral)
- Debate sobre el patrón
(T, error):- Un bando: los valores cero/nil deberían ser “útiles” incluso cuando
errorestá establecido. - Otro: en la mayoría de las API reales, los valores cero no significan nada o son peligrosos; la falta de tipos suma obliga a convenciones incómodas.
- Un bando: los valores cero/nil deberían ser “útiles” incluso cuando