mirror of
https://github.com/MedUnes/go-kata.git
synced 2026-03-12 21:55:53 +07:00
2.4 KiB
2.4 KiB
Kata 07: The Rate-Limited Fan-Out Client
Target Idioms: Rate Limiting (x/time/rate), Bounded Concurrency (x/sync/semaphore), HTTP Client Hygiene, Context Cancellation
Difficulty: 🟡 Intermediate
🧠 The "Why"
In many ecosystems, you slap a “rate limit middleware” in front of a thread pool and call it a day. In Go, people often:
- spawn too many goroutines (no backpressure),
- forget per-request cancellation,
- misuse
http.DefaultClient(timeouts/transport reuse), - implement “sleep-based” rate limiting (jittery, wasteful).
This kata forces explicit control over rate, in-flight concurrency, and cancellation.
🎯 The Scenario
You’re building an internal service that needs to fetch user widgets from a downstream API:
- API allows 10 requests/sec with bursts up to 20
- Your service must also cap concurrency at max 8 in-flight requests
- If any request fails, cancel everything immediately (fail-fast), and return the first error.
🛠 The Challenge
Implement FanOutClient with:
FetchAll(ctx context.Context, userIDs []int) (map[int][]byte, error)
1. Functional Requirements
- Requests must respect a QPS rate limit + burst.
- Requests must run concurrently but never exceed MaxInFlight.
- Results returned as
map[userID]payload. - On first error, cancel remaining work and return immediately.
2. The "Idiomatic" Constraints (Pass/Fail Criteria)
- Must use
golang.org/x/time/rate.Limiter. - Must use
golang.org/x/sync/semaphore.Weighted(or equivalent semaphore pattern) for MaxInFlight. - Must use
http.NewRequestWithContext. - Must NOT use
time.Sleepfor rate limiting. - Must reuse a single
http.Client(with a configuredTransport+Timeout). - Logging via
log/slog(structured fields: userID, attempt, latency).
🧪 Self-Correction (Test Yourself)
- If you spawn
len(userIDs)goroutines: you failed backpressure. - If cancellation doesn’t stop waiting callers: you failed context propagation.
- If QPS is enforced using
Sleep: you failed rate limiting. - If you use
http.DefaultClient: you failed HTTP hygiene.