Se un http.Client è già condiviso da richieste concorrenti, mantieni stabile il suo campo Transport. Un wrapper può sincronizzare quale trasporto completamente configurato riceve ogni successivo andata e ritorno:

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 e sync, inizializzalo prima di pubblicare il client:

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

slot.Set(nextTransport)

initialTransport e nextTransport devono essere esecutori di andata e ritorno non nil, completamente configurati e sicuri rispetto alla concorrenza. Costruisci ogni trasporto proxy prima di pubblicarlo e lascia invariata la sua configurazione mentre le richieste lo usano.

Il lock protegge solo l'istantanea del puntatore, quindi una richiesta lenta non trattiene il lock di instradamento per tutto il suo scambio di rete. Una richiesta che usa già l'istantanea precedente continua su quel trasporto; il cambio non la ripete né sposta la sua connessione.

Conserva e dismetti i vecchi trasporti lungo il ciclo di vita limitato dell'applicazione, lasciando che il lavoro in corso termini e chiudendo i pool inattivi quando opportuno. Un reindirizzamento può causare un altro RoundTrip dopo un cambio. Se un intero flusso di lavoro richiede un solo percorso, assegnalo al confine del flusso di lavoro invece di cambiare questo selettore condiviso a metà strada.

Articoli correlati