package main import ( "errors" "fmt" "sync" "time" ) // Worker simulates a task that might succeed or fail. func Worker(id int, shouldFail bool, resultCh chan<- string, errCh chan<- error, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("Worker %d: Starting task. ", id) time.Sleep(time.Duration(id*100) * time.Millisecond) // Simulate work if shouldFail { errCh <- fmt.Errorf("worker %d failed with a simulated error", id) return } resultCh <- fmt.Sprintf("Worker %d completed successfully", id) fmt.Printf("Worker %d: Finished task successfully. ", id) } func main() { numWorkers := 5 resultChannel := make(chan string, numWorkers) errorChannel := make(chan error, numWorkers) var wg sync.WaitGroup fmt.Println("Launching workers...") // Launch workers, some will fail for i := 0; i < numWorkers; i++ { wg.Add(1) // Make worker 2 and 4 fail shouldFail := (i == 1 || i == 3) go Worker(i+1, shouldFail, resultChannel, errorChannel, &wg) } // Wait for all workers to complete wg.Wait() // Close channels after all workers are done to signal no more data will come close(resultChannel) close(errorChannel) // Collect results fmt.Println(" --- Results ---") for res := range resultChannel { fmt.Println(res) } // Collect errors fmt.Println(" --- Errors ---") var collectedErrors []error for err := range errorChannel { collectedErrors = append(collectedErrors, err) fmt.Printf("Collected error: %v ", err) } if len(collectedErrors) > 0 { fmt.Printf(" Total %d errors aggregated. ", len(collectedErrors)) // You might return a multi-error here, or log them. combinedError := errors.Join(collectedErrors...) fmt.Printf("Combined error message: %v ", combinedError) } else { fmt.Println("No errors reported by workers.") } fmt.Println(" Main: All tasks processed.") }