// Exercise 01 — Concurrent URL Health Checker // // ASSIGNMENT // ---------- // Implement CheckAll so that it: // // 1. Checks every URL in `urls` with an HTTP GET. // 2. Runs AT MOST `limit` checks concurrently (bounded concurrency). // 3. Uses a per-request timeout of 5s AND respects the global `ctx` // (if ctx is cancelled, pending/unstarted checks must return ctx.Err()). // 4. Returns one Result per URL, at the SAME index as the input URL. // 5. Reuses a single http.Client and properly drains+closes response bodies // so connections are reused. // // Run the tests: go test -race ./01-url-health-checker/ // Run the demo: go run ./01-url-health-checker/ package main import ( "context" "fmt" "time" ) type Result struct { URL string Status int Latency time.Duration Err error } // CheckAll checks all URLs with at most `limit` in flight at once. // TODO: implement me. func CheckAll(ctx context.Context, urls []string, limit int) []Result { results := make([]Result, len(urls)) // TODO: // - semaphore (buffered channel) or worker pool for the concurrency limit // - sync.WaitGroup to wait for completion // - http.NewRequestWithContext for cancellation // - write results[i] from goroutine i (why is this safe without a mutex?) _ = ctx _ = limit return results } func main() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() urls := []string{"https://example.com", "https://httpbin.org/status/500", "https://nope.invalid"} for _, r := range CheckAll(ctx, urls, 2) { fmt.Printf("%-40s status=%d latency=%v err=%v\n", r.URL, r.Status, r.Latency, r.Err) } }