Uma breve nota antes dos comandos: somos a Geonode e vendemos proxies, o que significa que, para sermos honestos, um timeout do curl quase nunca é um problema relacionado com o proxy. Se as suas solicitações estão a atingir o tempo limite num servidor que é simplesmente lento, num host que está em baixo ou numa firewall que rejeita pacotes silenciosamente, encaminhá-las através de nós não altera nada, exceto a fatura. Os proxies ajudam quando o problema é de onde a sua solicitação parece vir — conteúdo com restrições geográficas, limites de taxa associados ao seu endereço ou um IP que foi bloqueado. Eles não tornam um servidor lento mais rápido. Defina primeiro os seus tempos de espera corretamente; poderá descobrir que nunca precisou de mais nada.
Exato. Eis o que a maioria das pessoas descobre da maneira mais difícil: o curl não tem um tempo de espera global predefinido. Tem um tempo de espera de ligação predefinido de 300 segundos, mas assim que a ligação é estabelecida, o curl fica alegremente à espera, indefinidamente, de uma resposta que nunca chega na totalidade. Num script de shell a ser executado no cron, isso traduz-se numa tarefa que nunca termina e num ficheiro de bloqueio que ninguém liberta.
Os dois tempos limite que importam
Tudo o resto é um aperfeiçoamento destes dois.
--max-time
(forma abreviada -m
) define o limite máximo de toda a operação. Segundo o manual do curl: «Tempo máximo, em segundos, que se permite que a operação de transferência demore.» Ligação, handshake, pedido, resposta, tudo isso. Quando o limite é atingido, o curl interrompe-se e sai com o código 28.
curl -m 10 https://example.com
Dez segundos no total; depois disso, o curl desiste, independentemente da fase em que se encontrava.
--connect-timeout
limita apenas a fase de configuração. O manual é preciso quanto ao que isso inclui: «A fase de ligação é considerada concluída quando a pesquisa de DNS e os handshakes TCP, TLS ou QUIC solicitados estiverem concluídos.» Assim que a ligação estiver estabelecida, esta opção deixa de se aplicar.
curl --connect-timeout 3 https://example.com
Três segundos para resolver o nome e concluir os handshakes. Depois disso, o curl aguarda o tempo que a transferência demorar.
Na prática, são desejáveis ambas as opções, e cada uma responde a questões diferentes:
| Opção | Abrange | Valor típico | Contra o que protege |
|---|
--connect-timeout | | | |
| DNS + handshake TCP/TLS/QUIC | 3–10 s | Hosts inativos, pacotes perdidos, falhas de DNS |
| --max-time
| Toda a operação | 10–60 s, dependendo da carga de trabalho | Respostas lentas, transferências paralisadas, fluxos intermináveis |
No total:
curl --connect-timeout 5 -m 30 https://example.com
Cinco segundos para estabelecer a ligação, trinta segundos para todo o processo. Se o host estiver inacessível, a falha ocorre aos cinco segundos em vez de aos trinta, o que é muito importante quando se está a percorrer uma lista de mil URLs.
Escolher valores que não sejam suposições
A abordagem habitual consiste em escolher um número redondo e ajustá-lo para cima sempre que algo falha. Isso acaba por convergir para um valor tão elevado que o tempo limite deixa de ter qualquer utilidade.
Um método melhor requer um comando adicional. O curl pode indicar onde o tempo foi realmente gasto: `
curl -o /dev/null -s -w "dns: %{time_namelookup}\nconnect: %{time_connect}\ntls: %{time_appconnect}\nttfb: %{time_starttransfer}\ntotal: %{time_total}\n" https://example.com
Execute esse comando no seu alvo real vinte ou trinta vezes e obterá uma distribuição, em vez de um palpite. Depois:
Defina --connect-timeout a partir de time_appconnect. Pegue no p95 e duplique-o aproximadamente. O tempo de ligação é dominado pelas idas e voltas da rede e é bastante estável; se demorar o dobro do tempo habitual, significa que há realmente algo de errado, em vez de ser apenas lento.
Defina --max-time a partir de time_total. Aqui, o multiplicador deve ser mais generoso — três a cinco vezes o p95 — porque o tempo total depende do tamanho da resposta e da carga do servidor, fatores que variam legitimamente. Um valor muito restrito em --max-time resulta em scripts instáveis que falham mesmo em dias normais de mau desempenho.
Dois ajustes específicos para a carga de trabalho. Se estiver a descarregar ficheiros grandes, --max-time é uma ferramenta totalmente inadequada, porque uma descarga legítima pode exceder qualquer limite fixo razoável — em vez disso, utilize a opção baseada na velocidade abaixo. E se estiver a chamar uma API que realiza trabalho real no lado do servidor, pergunte qual é o seu próprio tempo de espera e defina o seu um pouco mais alto; atingir o tempo de espera de 10 segundos num serviço que demora 12 a responder significa que paga pelo trabalho e descarta o resultado.
Segundos fracionários e precisão em milissegundos
Ambas as opções aceitam valores decimais, utilizando um ponto como separador, independentemente da sua configuração regional. Esta funcionalidade é suportada desde a versão 7.32.0 do curl.
curl --connect-timeout 0.5 -m 2.5 https://example.com
Meio segundo para estabelecer a ligação, dois segundos e meio no total. Útil para verificações de integridade e para qualquer ciclo em que um segundo inteiro de espera por cada falha se acumule.
Uma ressalva que vale a pena saber: a precisão diminui à medida que o valor aumenta. A documentação do curl indica que o tempo de espera real perde precisão à medida que a precisão decimal do tempo de espera especificado aumenta. Escrever --max-time 30.001 não é significativamente diferente de --max-time 30. Os decimais destinam-se a valores inferiores a um segundo; acima de alguns segundos, utilize números inteiros.
A opção relacionada --expect100-timeout também aceita decimais. Controla quanto tempo o curl aguarda um 100 Continue antes de enviar o corpo da solicitação, sendo o valor predefinido de um segundo. Se estiver a enviar corpos de grande dimensão via POST para um servidor que nunca responde com 100 Continue, estará a perder esse segundo em cada solicitação — reduza esse valor ou desative a expectativa com -H "Expect:".
Detetar transferências paralisadas que nunca atingem o tempo limite
Eis o problema. Uma transferência que envia um byte a cada poucos segundos nunca fica inativa, pelo que não se verifica qualquer tempo limite ao nível da ligação; e, se o parâmetro «--max-time
» estiver definido num valor suficientemente elevado para downloads legítimos de grande dimensão, também não se verificará. A solicitação simplesmente arrasta-se.
As opções --speed-limit
e --speed-time
tratam desta situação. Segundo o manual: «Se um download for mais lento do que --speed-limit
bytes por segundo durante um período de --speed-time
, a transferência é abortada.»
curl --speed-limit 1000 --speed-time 30 -O https://example.com/large-file.zip
Se a taxa de transferência se mantiver abaixo de 1000 bytes por segundo durante 30 segundos consecutivos, o curl interrompe — mais uma vez com o código de saída 28. Um download que decorre durante seis horas a um ritmo normal não é afetado. Um download que fica parado é interrompido em trinta segundos.
Este é o tempo de espera correto para qualquer coisa de tamanho imprevisível e integra-se bem:
curl --connect-timeout 5 --speed-limit 1000 --speed-time 30 -O https://example.com/large-file.zip
Falha rápida num host inativo, sem limite global, mas com um detetor de estagnação ao longo de todo o processo. Especificamente para downloads de ficheiros, este padrão deve estar presente em todos os scripts — consulte o nosso guia sobre download de ficheiros com o curl para conhecer as opções relacionadas.
Os tempos de espera e as tentativas de repetição interagem mal por predefinição
Esta é a parte que confunde as pessoas. A opção «
--retry N
» faz com que o curl tente resolver erros transitórios até N vezes. O que é fácil deixar escapar é que «--max-time
» se aplica a cada tentativa, e não ao comando como um todo, e que o curl espera entre tentativas com um recuo exponencial que começa num segundo e duplica a cada vez.
Portanto, isto:
curl -m 10 --retry 5 https://example.com
pode, legitimamente, demorar bem mais de um minuto: cinco tentativas de até dez segundos cada, mais tempos de espera de 1, 2, 4, 8 e 16 segundos. Se escreveu isto à espera de um limite máximo de dez segundos, estava errado por um fator de seis.
--retry-max-time
é a solução. Limita o tempo total gasto nas tentativas:
curl -m 10 --retry 5 --retry-max-time 40 https://example.com
Agora, o curl deixa de iniciar novas tentativas assim que decorrerem 40 segundos. Repare na formulação — não iniciará uma nova tentativa após o limite, mas uma tentativa já em curso prossegue até ao seu próprio «--max-time
». O verdadeiro pior caso é --retry-max-time
mais um --max-time
.
--retry-delay
substitui o recuo exponencial por uma espera fixa, o que torna o tempo de execução total previsível:
curl -m 10 --retry 3 --retry-delay 2 --retry-max-time 40 https://example.com
Mais um sinalizador que vale a pena conhecer: por predefinição, --retry
só é acionado num conjunto restrito de condições transitórias. --retry-all-errors
alarga-o consideravelmente — o manual descreve-o como uma repetição de tentativa de «todos os erros transitórios, incluindo os códigos de resposta FTP 4xx e 5xx». É verdadeiramente útil em scripts com redes instáveis e verdadeiramente perigoso quando utilizado com um POST não idempotente. Pense bem antes de o adicionar.
Tempos de espera quando se utiliza um proxy
Adicione -x
e o tempo de resposta altera-se, porque agora existem duas ligações em vez de uma: a sua ligação ao proxy e a ligação do proxy ao destino.
curl -x http://user:pass@proxy.example.com:9000 --connect-timeout 10 -m 45 https://example.com
Há três aspetos que se comportam de forma diferente em relação ao caso direto.
**--connect-timeout
mede o seu salto até ao proxy, e não o salto do proxy até ao destino.** No caso do HTTPS, o curl emite um ``CONNECT`
e o proxy estabelece a ligação seguinte; o tempo que isso demora conta para o ``--max-time
, e não para o ``--connect-timeout
`. Um tempo de espera de ligação curto não o protegerá, portanto, contra um proxy que aceite a sua ligação imediatamente e depois demore vinte segundos a chegar ao destino.
Os proxies residenciais são mais lentos, por motivos legítimos. O tráfego sai através de uma ligação de consumidor real, pelo que algumas centenas de milissegundos adicionais são normais e não constituem uma falha. Valores de tempo limite ajustados para uma ligação direta irão produzir falhas que parecem ser de proxies avariados, mas que, na realidade, são apenas uma questão de física. Efetue a medição através do proxy com o comando «-w
» acima e defina os valores com base nessa medição, e não nos números da sua ligação direta.
As falhas são ambíguas. Um código de saída 28 através de um proxy pode significar que o proxy está lento, que o destino está lento ou que o destino está deliberadamente a atrasar o seu pedido. Distinguir estas situações requer testar os componentes separadamente, o que é um tema suficientemente vasto para que tenhamos escrito um guia separado sobre como testar proxies.
Um padrão prático para pedidos via proxy: um «--connect-timeout
» generoso (10 s), um «--max-time
» definido com base no comportamento medido e não em suposições, e nada de «--retry-all-errors
», porque, através de um proxy, um código 5xx significa frequentemente que o destino está a recusar o pedido, em vez de estar a passar por um momento difícil, e repetir a tentativa só piora a situação.
Interpretar o código de saída
O código de saída do curl indica em que fase ocorreu a falha, o que representa mais informação do que a maioria dos scripts se dá ao trabalho de utilizar.
| Código | Nome | Significado |
|---|
| 6 | CURLE_COULDNT_RESOLVE_HOST | Falha no DNS — sem tempo de espera envolvido |
| 7 | CURLE_COULDNT_CONNECT | «Falha ao ligar-se (connect()) ao anfitrião ou proxy» |
| 28 | CURLE_OPERATION_TIMEDOUT | «O período de tempo limite especificado foi atingido» |
| 56 | CURLE_RECV_ERROR | Falha na receção de dados de rede — ligação interrompida a meio da transferência |
As descrições provêm da referência de erros da libcurl.
A distinção entre 7 e 28 é a mais útil. O código 7 significa que a ligação foi ativamente recusada — houve uma resposta a dizer «não», rapidamente. O código 28 significa que não houve resposta atempada. O primeiro indica normalmente uma porta errada ou um serviço encerrado; o segundo indica um pacote perdido, uma firewall com filtragem silenciosa ou um anfitrião genuinamente sobrecarregado. Tentar novamente faz sentido no caso do código 28 e, normalmente, é inútil no caso do código 7.
Num script:
curl --connect-timeout 5 -m 30 -sS https://example.com > out.txt
case $? in
0) echo "ok" ;;
6) echo "dns failure" ;;
7) echo "connection refused" ;;
28) echo "timed out" ;;
*) echo "other failure" ;;
esac
Note que os três mecanismos de tempo limite — --max-time, --connect-timeout e o par de limites de velocidade — devolvem o código 28. O código de saída indica que um limite foi atingido, mas não especifica qual. Se precisar de saber, utilize -w "%{time_total}" e compare com os valores que configurou.
Quando não definir um tempo limite
Contrariamente ao que se costuma aconselhar, há casos em que um tempo limite não é a solução adequada.
Transferências interativas. Se estiver a digitar um comando curl num terminal para descarregar um ficheiro grande, é o próprio utilizador que define o tempo limite. Pode ver a barra de progresso e premir Ctrl-C. Adicionar -m aqui apenas causa o incómodo de um download que fica parado nos 90%.
Fluxos de longa duração. Eventos enviados pelo servidor, acompanhamento de registos, respostas fragmentadas que permanecem abertas por definição — --max-time irá encerrar estes processos exatamente no momento errado. Utilize --speed-limit e --speed-time se precisar de um detetor de paralisação, ou não utilize nada.
Qualquer coisa já sujeita a um limite externo. Se o curl for executado sob timeout(1), uma unidade do systemd com RuntimeMaxSec ou uma etapa de CI com o seu próprio orçamento, uma segunda camada não acrescenta nada além de um segundo número para manter a sincronização. Escolha a camada que produz a mensagem de erro que pretende ler e defina-a aí.
Como solução para um destino lento. Um tempo limite faz com que uma solicitação lenta falhe mais rapidamente. Não faz com que ela seja bem-sucedida. Se o seu verdadeiro problema é que um servidor demora 40 segundos a responder, as opções são o armazenamento em cache, paginação, um endpoint diferente ou uma conversa com quem o gere — e é aqui que vamos repetir a advertência do início, uma vez que é a razão mais comum pela qual as pessoas compram proxies e uma das poucas coisas que os proxies não conseguem resolver de todo. Os nossos preços começam em 0,79 $/GB para tráfego residencial e 0,14 $/GB para centros de dados, verificados em setembro de 2026, e nenhum deles irá acelerar um servidor de origem lento.
Perguntas frequentes
Qual é o tempo limite predefinido no curl?
Não existe um tempo limite global predefinido — o curl aguarda indefinidamente por uma resposta assim que estabelece a ligação. A fase de ligação tem, no entanto, um tempo limite predefinido de 300 segundos. É por isso que -m é importante nos scripts: sem ele, uma solicitação bloqueada faz com que o script fique bloqueado.
Qual é a diferença entre --max-time e --connect-timeout?
O --connect-timeout abrange apenas a resolução de DNS e os handshakes TCP/TLS/QUIC, e deixa de ser aplicado assim que a ligação é estabelecida. O --max-time abrange toda a operação do início ao fim, incluindo a transferência da resposta. Utilize ambos — um tempo de espera de ligação curto para detetar rapidamente falhas em hosts inativos e um tempo máximo mais longo como limite geral.
Por que razão o meu comando curl demora mais tempo do que o tempo de espera que defini?
Quase sempre devido às tentativas de repetição. --max-time aplica-se por tentativa, e --retry adiciona tanto tentativas extra como um recuo exponencial entre elas. Adicione --retry-max-time para limitar o total e lembre-se de que o pior cenário é esse valor mais mais uma --max-time.
Como defino um tempo limite do curl em milissegundos?
Utilize um valor decimal: --connect-timeout 0.25 corresponde a 250 milissegundos. Tanto --max-time como --connect-timeout aceitam decimais separados por um ponto, uma funcionalidade suportada desde o curl 7.32.0. A precisão é melhor quando os valores são inferiores a alguns segundos; para valores maiores, a precisão da parte fracionária diminui.
Que código de saída devolve o curl em caso de tempo limite?
28, CURLE_OPERATION_TIMEDOUT. Todos os três mecanismos de tempo limite devolvem este código, pelo que o código indica que foi atingido um limite, mas não especifica qual. Compare com o 7 (ligação recusada) e o 6 (falha de DNS), que têm significados diferentes e, normalmente, não devem ser repetidos.
Como posso definir um tempo limite para um download lento sem interromper ficheiros grandes?
Utilize --speed-limit e --speed-time em vez de --max-time. Estes só abortam o download quando a taxa de transferência permanece abaixo de um limiar durante um período prolongado, pelo que um download legítimo com várias horas de duração não é afetado, enquanto um download parado é interrompido rapidamente.
Os tempos de espera funcionam de forma diferente através de um proxy?
Sim. --connect-timeout mede apenas a sua ligação ao proxy; a ligação do proxy ao destino é avaliada em --max-time. Os proxies residenciais também acrescentam latência real, pelo que valores ajustados para ligações diretas produzirão falhas falsas. Faça a medição através do proxy e defina os valores com base nisso.
Posso definir um tempo limite apenas para a resolução de DNS?
Não como uma opção separada — o DNS está incluído em --connect-timeout. Se precisar de limitar especificamente o DNS, faça a resolução separadamente e passe o resultado com --resolve, o que ignora completamente a própria pesquisa do curl.
Conclusão
Existem duas opções que cobrem praticamente todos os casos: --connect-timeout para uma falha rápida quando um anfitrião está inacessível, e --max-time para o limite máximo geral. Defina ambas, em todos os scripts, sempre. A configuração predefinida de esperar indefinidamente é uma escolha razoável para uma ferramenta interativa, mas péssima para a automatização.
Vale a pena repetir os dois aspetos que mais confundem as pessoas. --max-time aplica-se por tentativa, pelo que qualquer utilização de --retry requer --retry-max-time em simultâneo; caso contrário, o seu comando de dez segundos transforma-se num comando de um minuto. Além disso, um limite de tempo fixo não é a ferramenta adequada para transferências de tamanho imprevisível — utilize --speed-limit com --speed-time e obterá um detetor de bloqueios que não interfere com downloads longos legítimos.
Defina os valores com base em medições, em vez de num número redondo que pareça adequado. Uma execução de curl -w no seu alvo real fornece-lhe uma distribuição, e um tempo limite derivado dessa distribuição falha quando algo está genuinamente errado, em vez de falhar sempre que a rede tiver uma tarde normal de mau desempenho.