Si un http.Client ya es compartido por solicitudes concurrentes, mantenga su campo Transport estable. Un envoltorio puede sincronizar qué transporte totalmente configurado recibe cada recorrido posterior:

type routeSlot struct {
    mu sync.RWMutex
    current http.RoundTripper
}

func (s *routeSlot) RoundTrip(r *http.Request) (*http.Response, error) {
    s.mu.RLock()
    current := s.current
    s.mu.RUnlock()
    return current.RoundTrip(r)
}

func (s *routeSlot) Set(next http.RoundTripper) {
    s.mu.Lock()
    s.current = next
    s.mu.Unlock()
}

Con net/http y sync, inicialícelo antes de publicar el cliente:

slot := &routeSlot{current: initialTransport}
client := &http.Client{Transport: slot}

slot.Set(nextTransport)

initialTransport y nextTransport deben ser ejecutores de recorridos no nulos, totalmente configurados y seguros frente a la concurrencia. Construya cada transporte de proxy antes de publicarlo y deje su configuración sin cambios mientras las solicitudes lo usan.

El bloqueo protege solo la instantánea del puntero, así que una solicitud lenta no retiene el bloqueo de enrutamiento durante todo su intercambio de red. Una solicitud que ya usa la instantánea anterior continúa en ese transporte; el cambio no la repite ni mueve su conexión.

Conserve y retire los transportes antiguos a través del ciclo de vida acotado de la aplicación, permitiendo que el trabajo en curso termine y cerrando los grupos inactivos cuando corresponda. Una redirección puede provocar otro RoundTrip después de un cambio. Si todo un flujo de trabajo requiere una ruta, asígnela en el límite del flujo de trabajo en lugar de cambiar este selector compartido a mitad de camino.

Artículos relacionados