Sobes.tech
Middle+

Task: "Parallel URL processing with timeout limit" Write a function fetchAll(urls []string, maxParallel int, timeout time.Duration) map[string]string, which: 1. Performs an HTTP GET request for each URL (using http.Get). 2. Returns a map[string]string where the key is the URL, and the value is the response body (as a string) or an empty string on error/timeout. 3. Executes no more than maxParallel requests simultaneously. 4. The total runtime of the function should not exceed timeout. If the timeout expires, all unfinished requests are interrupted, and the function returns what it has. 5. Use context for cancellation.

sobes.tech AI

Answer from AI

go package main

import ( "context" "io/ioutil" "net/http" "sync" "time" )

func fetchAll(urls []string, maxParallel int, timeout time.Duration) map[string]string { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel()

results := make(map[string]string)
var mu sync.Mutex
sem := make(chan struct{}, maxParallel) // semaphore to limit parallelism
var wg sync.WaitGroup

for _, url := range urls {
	select {
	case <-ctx.Done():
		break
	default:
		wg.Add(1)
		sem <- struct{}{} // acquire slot

		go func(u string) {
			defer wg.Done()
			defer func() { <-sem }() // release slot

			req, err := http.NewRequestWithContext(ctx, "GET", u, nil)
			if err != nil {
				mu.Lock()
				results[u] = ""
				mu.Unlock()
				return
			}

			resp, err := http.DefaultClient.Do(req)
			if err != nil {
				mu.Lock()
				results[u] = ""
				mu.Unlock()
				return
			}
			defer resp.Body.Close()

			body, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				mu.Lock()
				results[u] = ""
				mu.Unlock()
				return
			}

			mu.Lock()
			results[u] = string(body)
			mu.Unlock()
		}(url)
	}
}

wg.Wait()
return results

}