Mission 07 · 45-60 min
The provider stops answering
connect vs read timeout, thread exhaustion, fail fast
Read lesson 07 first: The provider stops answering (10 min)
You are reading the mission. Its ./lab commands run against a Java service, Postgres and k6 on your own machine: start dacospace locally to get Run buttons, live Grafana panels, load test results and a notebook. Setup on GitHub.
Scenario
The payment provider does not fail. It does something worse: it accepts the connection and never answers. No error, no log line, just waiting. Twenty seconds later even the price list is dead, although mission 05 already moved the payment out of the transaction.
1. Predict first
Open PaymentClient.java. How long will a charge wait for an answer that never comes? Where does the
waiting thread come from, and how many of them does Tomcat have?
At 10 orders per second, after how many seconds are all Tomcat threads stuck?
2. Break it
./lab chaos payment hang./lab load mixed
Watch Tomcat threads (Saturation tab) and p95 per endpoint. The test takes longer than usual: k6 itself waits up to 30 s per request. Then:
./lab chaos payment normal
Requests that were already hanging keep their threads for a while. Restart the app before measuring again.
3. The 4 steps (on paper)
- What is broken: which resource ran out this time? It is not the connection pool.
- Numbers: threads needed = orders per second × seconds each one waits. Compare with 200.
- Path: request thread →
place()→PaymentClient.charge()→ ... waits where? - What can break: what is the longest you are willing to wait for a payment answer, and why that number?
4. Fix it
Give the payment client a connect timeout (how long to wait for the TCP connection) and a read timeout (how long to wait for the answer). Choose the values from data: the provider's normal p95 is visible in the Payments tab. Write down the numbers you picked and why.
Make sure an order whose charge timed out does not keep its reserved stock.
./lab chaos payment hang./lab load mixed./lab chaos payment normal./lab sql "SELECT status, count(*) FROM orders WHERE created_at > now() - interval '5 minutes' GROUP BY status"
5. Evidence
| Before | After | |
|---|---|---|
| p95 list products (provider hangs) | ||
| p95 place order | ||
| max busy Tomcat threads | ||
| order statuses written |
6. In your own words
One sentence: why is "no timeout" never the safe default?
Check question
Your read timeout is 2 s and you later add 2 retries (mission 08). The provider hangs. How long does one order now wait at worst, and how many threads does 10 orders/s keep busy?
Java corner
JdkClientHttpRequestFactorytakes ajava.net.http.HttpClient. Which of the two timeouts lives on theHttpClientand which on the factory?- Which exception type does
RestClientthrow on a read timeout? Find it in the app log.