Se um http.Client já é compartilhado por solicitações concorrentes, mantenha seu campo Transport estável. Um invólucro pode sincronizar qual transporte totalmente configurado cada ida e volta posterior recebe:

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()
}

Com net/http e sync, inicialize-o antes de publicar o cliente:

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

slot.Set(nextTransport)

initialTransport e nextTransport devem ser executores de ida e volta não nulos, totalmente configurados e seguros quanto à concorrência. Construa cada transporte de proxy antes de publicá-lo e deixe sua configuração inalterada enquanto as solicitações o usam.

O bloqueio protege apenas o instantâneo do ponteiro, então uma solicitação lenta não retém o bloqueio de roteamento durante toda a troca de rede. Uma solicitação que já usa o instantâneo anterior continua nesse transporte; a troca não a repete nem move sua conexão.

Mantenha e retire transportes antigos durante o ciclo de vida limitado da aplicação, permitindo que o trabalho em andamento termine e fechando pools ociosos quando apropriado. Um redirecionamento pode causar outro RoundTrip após uma troca. Se um fluxo de trabalho inteiro exigir uma rota, atribua-a na fronteira do fluxo de trabalho em vez de alterar este seletor compartilhado no meio do caminho.

Artigos relacionados