package main import ( "fmt" "math/rand" "time" ) // simulateExternalCall simulates an external API call that might succeed or fail. func simulateExternalCall(serviceName string, delay time.Duration, successRate float64) (string, error) { time.Sleep(delay) if rand.Float64() < successRate { return fmt.Sprintf("Data from %s (took %s)", serviceName, delay), nil } return "", fmt.Errorf("failed to get data from %s", serviceName) } func main() { rand.Seed(time.Now().UnixNano()) // For random delays/success resultChan := make(chan string) done := make(chan struct{}) // To signal other goroutines to stop once a result is found services := []struct { name string delay time.Duration successRate float64 }{ {"Service A", 300 * time.Millisecond, 0.7}, {"Service B", 100 * time.Millisecond, 0.9}, {"Service C", 500 * time.Millisecond, 0.5}, } for _, s := range services { go func(sName string, sDelay time.Duration, sSuccessRate float64) { select { case <-done: // Check if another goroutine already succeeded return default: data, err := simulateExternalCall(sName, sDelay, sSuccessRate) if err != nil { // Log error or send to an error channel if needed, but for 'first success' pattern, we ignore and wait for others return } select { case resultChan <- data: close(done) // Signal others to stop if we found a result case <-done: // If another goroutine already sent a result, don't send ours } } }(s.name, s.delay, s.successRate) } select { case result := <-resultChan: fmt.Printf("First successful result: %s ", result) case <-time.After(1 * time.Second): // Global timeout for any service to respond fmt.Println("No service returned a successful result within timeout.") } // Give a moment for other goroutines to clean up or realize done is closed time.Sleep(100 * time.Millisecond) }