אם 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 נוסף אחרי החלפה. אם תהליך עבודה שלם דורש מסלול אחד, הקצו אותו בגבול תהליך העבודה במקום לשנות את הבורר המשותף הזה באמצע.

מאמרים קשורים