Urgent.News

What's breaking now, across thousands of outlets.

Tech

The Retry That Fired After the Stream Ended

The Retry That Fired After the Stream Ended A stream can succeed and still look failed to your client. That gap is where retry logic doubles side effects. The current AI conversation is full of fatigue and agent demos. The useful question is smaller: what did the generated retry wrapper actually do? I'll use a synthetic repro, not a customer incident. The failure is real enough to run on your…

A stream can succeed without looking successful to clients. Retry logic adds complications. The main question is: what did the retry wrapper actually accomplish? A synthetic example will illustrate. The failure is real and can be reproduced locally. The scenario involves one endpoint, client, and assertion.

The symptom: Submitting a job once results in two rows in the database without any exception appearing in logs. The client logs a retry because the stream ended without a terminal event. This does not necessarily indicate a failure. The server might have accepted the job and completed the work, but clients often misinterpret the absence of a done event as a request failure.

To build a server that closes cleanly, a FastAPI app can be created. It streams one progress event but does not send a terminal event. Upon POSTing to the /jobs endpoint, the job ID is recorded in a list. An events generator yields a progress event followed by a sleep of 0.05 seconds. However, no terminal event is sent before closing the response. The server is started using uvicorn, and curl is used to make a POST request to the endpoint. The raw stream output stops after the progress event, with no error or done event.

The client code attempts to implement a retry wrapper. It retries if a terminal event is missing. When running the test, it is observed that two POST requests are made instead of one. This indicates that the retry wrapper is duplicating the POST request. The test demonstrates that the bug lies in the retry wrapper.

To classify the failure, several questions must be answered in order. Did the server receive any bytes? Check the access log or an idempotency store. Did the failure occur before the first response byte? If so, a retry is usually safe. Did the stream break after the first byte? In this case, querying the job state instead of reposting is recommended.

Did the stream close cleanly after a 200 response? Treat it as a success, then fix the contract. Did the client time out while the server continued working? Retrying in this scenario can lead to duplicated work.

A decision table is provided to help determine whether a POST can be safely retried. If the failure point is the connection refused or 503 status before the body, it is safe to backoff and retry. If the stream closes mid-body without a terminal event, retrieving the job state via GET /jobs/{id} is the better action. Lastly, if the client times out while the server remains alive, polling the job state by key is advised.

To fix the contract, both the server and client must be modified. The server must always end the stream, while the client must refrain from blindly retrying non-idempotent POST requests. An idempotency key and a terminal event should be added to both the server and client. This will ensure that the generated retry wrapper performs as intended and does not duplicate server-side jobs.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

The Mean Looked Fine. Goodput Said No.

Mean latency is a liar. Goodput is the number I keep now. I learned this the boring way. I pointed a small agent loop at a free model endpoint. The average looked fine. Users still complained. Why?

  • Mean latency can be misleading as it ignores slowest users
  • Goodput measures share of requests meeting latency budget
  • Redefining success as goodput reveals poor performance for some users

Estimating moving costs without an address form: building a privacy-first quote calculator

Most moving quote tools start the same way: enter your name, email, phone, current address, destination address — and then the calls begin. We built ours backwards.

  • Fast Movers' quote calculator doesn't require personal data like name, email, or addresses
  • Cost estimation relies on distance, shipment weight, and season, not user accounts
  • Tool shows price ranges and assumptions to build trust and transparency

Built, deployed, and shipped 5 image tools solo. Now the hard part: getting users.

Fair question. remove.bg and TinyPNG are excellent single-purpose tools — I still use both. My pitch is different: One suite instead of 5 tabs Bulk mode built-in (20 files at a time on most tools) No…

  • Author built and deployed 5 free image tools without signups
  • Tools include background remover, upscaler, compressor, converter, PDF generator
  • Current 40 users aim for 10,000 sessions to meet Ezoic threshold

More from Saturday 17 October →