Перемикання проксі-маршрутів Go HTTP без зміни Client.Transport
Використовуйте синхронізовану обгортку RoundTripper, щоб опублікувати новий налаштований проксі-транспорт, не змінюючи поле працюючого http.Client.
Якщо http.Client уже спільно використовується паралельними запитами, тримайте його поле Transport стабільним. Обгортка може синхронізувати, який повністю налаштований транспорт отримує кожен наступний обіг:
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()
}З net/http і sync ініціалізуйте його перед публікацією клієнта:
slot := &routeSlot{current: initialTransport}
client := &http.Client{Transport: slot}
slot.Set(nextTransport)initialTransport і nextTransport мають бути не-nil, повністю налаштованими й безпечними щодо паралельності. Створюйте кожен проксі-транспорт перед його публікацією і не змінюйте його конфігурацію, поки запити його використовують.
Блокування захищає лише знімок вказівника, тож повільний запит не утримує блокування маршрутизації впродовж усього мережевого обміну. Запит, який уже використовує попередній знімок, продовжує на цьому транспорті; перемикання не перезапускає його й не переносить його з'єднання.
Зберігайте й виводьте старі транспорти в межах обмеженого життєвого циклу застосунку, дозволяючи поточній роботі завершитися та закриваючи простоюючі пули, коли це доречно. Переспрямування може спричинити ще один RoundTrip після перемикання. Якщо всьому робочому процесу потрібен один маршрут, призначте його на межі робочого процесу, а не змінюйте цей спільний селектор на півдорозі.