context en database/sql y gRPC
database/sql y google.golang.org/grpc fueron diseñados en torno a context.Context desde el primer día.
Busca en todas las páginas de la documentación
database/sql y google.golang.org/grpc fueron diseñados en torno a context.Context desde el primer día.
Pasar ctx a los métodos de consulta y RPC vincula el trabajo de la base de datos y la red al mismo árbol de cancelación que tu manejador HTTP.
Usa QueryContext, ExecContext y BeginTx con context para cada llamada a la base de datos con ámbito de solicitud.
Los métodos cliente y servidor de gRPC aceptan ctx como el primer argumento; las fechas límite se propagan como tiempos de espera de RPC.
Los RPCs de streaming deben verificar ctx.Done() entre las llamadas Recv y Send.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
func GetOrder(ctx context.Context, db *sql.DB, id string) (string, error) {
var status string
err := db.QueryRowContext(ctx, `SELECT status FROM orders WHERE id = ?`, id).Scan(&status)
return status, err
}Cuándo usar esto:
Query/Exec sin Context en cualquier ruta de código accesible desde manejadores HTTP o gRPC.ctx.Done() se active para evitar fugas de goroutines.package main
import (
"context"
"database/sql"
"fmt"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
_ "github.com/mattn/go-sqlite3"
)
func queryStatus(ctx context.Context, db *sql.DB) (string, error) {
ctx, cancel := context.WithTimeout(ctx, 200*time.Millisecond)
defer cancel()
var s string
err := db.QueryRowContext(ctx, `SELECT 'shipped'`).Scan(&s)
return s, err
}
func dialGRPC(ctx context.Context) (*grpc.ClientConn, error) {
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
return grpc.DialContext(ctx, "localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
}
func main() {
db, _ := sql.Open("sqlite3", ":memory:")
defer db.Close()
parent, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
status, err := queryStatus(parent, db)
fmt.Println(status, err)
_, err = dialGRPC(parent)
fmt.Println("grpc dial:", err)
}Lo que esto demuestra:
QueryRowContext respeta la cancelación del padre y el tiempo de espera hijo local.grpc.DialContext se bloquea solo hasta que el context termina o la conexión tiene éxito.database/sql pasa el context a las interfaces QueryerContext del controlador; el comportamiento de cancelación depende del soporte del controlador.ctx termina en lugar de bloquearse para siempre.Tx usan BeginTx(ctx, opts); commit y rollback son rápidos, pero las sentencias en curso ya deberían usar el context de la tx.codes.DeadlineExceeded cuando queda tiempo insuficiente.| Método | Variante de Context |
|---|---|
| Query | QueryContext |
| Exec | ExecContext |
| Prepare | PrepareContext |
| Begin | BeginTx(ctx, *TxOptions) |
| Ping | PingContext |
func consume(stream pb.Service_StreamServer) error {
ctx := stream.Context()
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
msg, err := stream.Recv()
if err != nil {
return err
}
_ = msg
}
}Los flujos de servidor exponen Context(); los flujos de cliente aceptan el ctx del llamador en la invocación inicial del RPC.
Las llamadas al cliente de Kubernetes desde los reconciliadores deben pasar el context de reconciliación a las solicitudes de API para que laswatches se detengan cuando el gestor se apaga.
BeginTx con ctx; mantener las transacciones cortas.ctx.Done() o manejar los errores de Recv rápidamente.DialContext con ctx limitado.ctx.Deadline() en el lado del servidor y ajustar el trabajo.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
db.SetConnMaxLifetime | Higiene del pool | Cancelación por solicitud (usar ctx) |
statement_timeout de SQL | Límite de consulta independiente del controlador | Reemplazar completamente el ctx de la aplicación |
| gRPC keepalive | Detectar conexiones muertas | Aplicación de fecha límite orientada al usuario |
| Sesión ORM sin ctx | Trabajos por lotes internos heredados | Manejadores de solicitudes en línea |
| Cola de mensajes para trabajo lento | Procesamiento de minutos | Lecturas en el lado del usuario de subsegundos |
La mayoría de los controladores modernos lo hacen; verifica para tu base de datos en la documentación del controlador.
Combina con tiempos de espera a nivel de SQL como red de seguridad.
Sí, para rutas de solicitud: esperar una conexión libre debe respetar la cancelación del cliente.
Usa metadata.NewOutgoingContext en clientes y lee de metadata.FromIncomingContext en servidores.
Mantén los metadatos pequeños y seguros para la red.
Pasa ctx a la llamada inicial de Client; verifica ctx.Done() entre fragmentos de Send.
Sí: los contextos son seguros para lecturas concurrentes.
Usa transacciones separadas para escrituras que deban aislarse.
errgroup.WithContext cancela a los hermanos cuando una consulta falla.
Pasa el ctx del grupo a cada QueryContext.
Las migraciones de larga duración pueden usar context.Background() con cancelación controlada por operaciones.
Los manejadores de solicitudes en línea no deben ejecutar migraciones.
Mapea context.Canceled a aborto del cliente; DeadlineExceeded a respuestas de tiempo de espera.
No los trates como un 500 genérico cuando el cliente inició la detención.
PrepareContext respeta ctx; las sentencias cacheadas aún se ejecutan con QueryContext por llamada.
Los interceptores unarios y de stream pueden aplicar fechas límite y adjuntar valores antes de que se ejecuten los manejadores.
Comparte lógica entre el middleware HTTP y gRPC siempre que sea posible.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado GC de Green Tea, go fix modernizers - verifica el parche en la compilación), chi (última - verifica en la compilación), gin (última - verifica en la compilación), echo (última - verifica en la compilación), google.golang.org/grpc (última - verifica en la compilación), sigs.k8s.io/controller-runtime (última - verifica en la compilación), kubebuilder (última - verifica en la compilación), tinygo (última - verifica los objetivos de la placa en la compilación), wazero (última - verifica en la compilación) y golangci-lint (última - verifica el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 19 jul 2026