Timing out provider calls so one slow API can't hang the whole page
When I first wired up ramrom.io, the flow looked simple: a visitor pastes a video link, my PHP script calls the provider API, and the download button appears. What I did not think about was what happens when the provider
When I first wired up ramrom.io, the flow looked simple: a visitor pastes a video link, my PHP script calls the provider API, and the download button appears. What I did not think about was what happens when the provider API just... does not answer.
It did not answer one afternoon. The request sat there. My script sat there with it. The visitor sat there with both of us, staring at a spinner that never stopped.
That is the thing about a plain cURL call in PHP: by default, it will wait. There is no built-in sense of urgency. If the remote server takes thirty seconds to respond, your page takes thirty seconds. If it never responds, your page effectively never responds either. On shared hosting, that is worse than a slow page — a pile of hanging PHP processes can eat the account's limits and take the whole site down with it.
The fix is one option, and it is boring
The fix is CURLOPT_TIMEOUT. One line, set to a number of seconds, and cURL gives up when the clock runs out:
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
Fifteen seconds is the number I settled on. It is long enough for a healthy provider to answer — most responses come back in two or three seconds — and short enough that a visitor never watches a spinner for a whole minute. There is a companion option too, CURLOPT_CONNECTTIMEOUT, which caps only the time spent connecting to the server. I set that to five seconds. If the server cannot even open a connection in five seconds, it is not going to serve me well anyway.
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
A timeout is not an error message
The important part is not the two lines. It is what happens after them. When cURL times out, curl_exec() returns false, and the error code is CURLE_OPERATION_TIMEDOUT. If you do nothing with that, the visitor gets a blank page or a cryptic error. So the timeout is only half the job — the other half is turning it into an honest message:
$response = curl_exec($ch);
if ($response === false) {
$err = curl_errno($ch);
if ($err === CURLE_OPERATION_TIMEDOUT) {
// tell the visitor plainly: the service is slow right now
}
}
On the front end that becomes a short, plain line: "The video service is taking too long to respond. Please try again in a moment." No spinner that spins forever, no technical jargon, no pretending the link itself was wrong. A timeout is my problem, not the visitor's, and the message should say so.
Why not just make the timeout longer?
It is tempting to set the timeout to sixty seconds and hope the provider eventually answers. Two reasons not to. First, the visitor is gone long before sixty seconds — nobody waits that long for a download button. Second, shared hosting is a shared pool. Every hanging PHP process is a slot that cannot serve anyone else. A handful of visitors pasting links during a provider outage could fill that pool with processes that are all just waiting. Fifteen seconds keeps the damage small.
The retry question
One timeout does not mean the request is dead. A single slow response can be a blip, so I allow a small number of retries — but the retry loop respects the same limit. Each attempt still gets fifteen seconds, and the whole loop stops quickly. Retrying without a timeout is just the same hang with extra steps.
The lesson
Every call to a server I do not control needs a deadline. It does not matter how reliable the provider usually is; the one afternoon it stalls is the afternoon your visitors decide the site is broken. Two options, one error check, and a plain message — that is the whole fix. It took me ten minutes to add and it has saved the site from looking dead more times than I can count.
That is the rule I now follow on every outbound call in the project: if I did not set a timeout, the call is not finished yet.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.