Golang / GoLang Concurrency Mastery Interview Questions
How do you implement a hedged request pattern using select and goroutines?
A hedged request sends the same request to multiple backends simultaneously and returns the first successful response, cancelling the rest. It trades slightly higher resource use for dramatically lower tail latency — a technique from Google's Bigtable paper.
func hedgedFetch(ctx context.Context, urls []string) ([]byte, error) { ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() // cancels all in-flight requests when we return type result struct{ data []byte; err error } ch := make(chan result, len(urls)) // buffered â goroutines can exit freely for _, url := range urls { url := url go func() { req, _ := http.NewRequestWithContext(ctx, "GET", url, nil) resp, err := http.DefaultClient.Do(req) if err != nil { ch <- result{err: err}; return } defer resp.Body.Close() data, err := io.ReadAll(resp.Body) ch <- result{data: data, err: err} }() } var errs []error for i := 0; i < len(urls); i++ { r := <-ch if r.err == nil { cancel() // cancel remaining requests return r.data, nil } errs = append(errs, r.err) } return nil, fmt.Errorf("all backends failed: %v", errs) } // Timed hedging â send to fallback only after 100ms func timedHedge(ctx context.Context, primary, fallback string) ([]byte, error) { ch := make(chan result, 2) go func() { ch <- fetch(ctx, primary) }() select { case r := <-ch: if r.err == nil { return r.data, nil } case <-time.After(100 * time.Millisecond): go func() { ch <- fetch(ctx, fallback) }() } for i := 0; i < 2; i++ { if r := <-ch; r.err == nil { return r.data, nil } } return nil, errors.New("all requests failed") }
More Related questions...