Skip to content

Retry HTTP requests on dead connections#76

Merged
lmeilibr merged 4 commits into
BCR-CX:mainfrom
monteiroliveira:main
Apr 17, 2026
Merged

Retry HTTP requests on dead connections#76
lmeilibr merged 4 commits into
BCR-CX:mainfrom
monteiroliveira:main

Conversation

@monteiroliveira
Copy link
Copy Markdown
Collaborator

@monteiroliveira monteiroliveira commented Apr 17, 2026

Retry Request em conexões mortas

Prefácio

O fix anterior (commit 30f8968) introduziu um refresh proativo de sessão baseado em um threshold de 5 minutos (CONNECTION_MAX_AGE). Apesar de ajudar em alguns casos, não previne erros de RemoteDisconnected — o servidor ou um load balancer intermediário pode fechar a conexão TCP a qualquer momento antes da janela de 5 minutos expirar, deixando o próximo request em um socket morto.

Este PR introduz um método centralizado _request() com uma estratégia de retry reativo por cima do refresh proativo existente, além de preservar o suporte a params no get() e o método get_raw() para URLs pré-construídas.

CHANGELOG

  • 15b053bfdb88: Retry HTTP requests on dead connections instead of only refreshing

Introduz _request() como ponto único de dispatch para todos os métodos HTTP (get, post, put, patch, delete, post_multipart). Em caso de ConnectionError ou RemoteDisconnected, a sessão é fechada, uma nova é criada e o request é retentado exatamente uma vez. Se o retry também falhar, a exceção é propagada normalmente. Também preserva get(params=) e get_raw() para URLs com brackets literais (e.g. page[size]).

  • c18d5f061449: Delegate get_raw to _request_raw with connection retry

Extrai _prepare_and_send e _request_raw para que get_raw se beneficie da mesma lógica de retry em conexões mortas que os demais métodos HTTP.

  • 21dc0c40f861: Add tests for get_raw and _request_raw connection retry

Adiciona 5 novos testes cobrindo: happy path, error mapping, retry em ConnectionError, retry em RemoteDisconnected e propagação de falha no retry.

  • a9492e784aab: Bump version to 0.9.1

REQUISITOS PARA O PR

  • Ajuste as Flags referente ao PR (conforme os issues);
  • Escreva uma boa descrição para o PR. Se fizer algo de qualquer jeito, muito provavelmente vai e DEVE ser recusado;
  • Declare se o PR está com os testes atualizados;
  • Para aprovação, é necessário o CI passar (com algumas exceções);
  • Utilize as configs de pre-commit antes de subir o PR;
  • Confira se a sua branch está atualizada com a branch default de repositório;
  • Não há *.log, print, código comentado ou dados sensíveis no diff (Não deixe código comentado e verifique seus commits antes de dar push, é exatamento para isso que o git serve).

The previous fix (commit 30f8968) introduced a proactive session refresh
based on a 5-minute age threshold (CONNECTION_MAX_AGE). While this helps
in some cases, it does not prevent RemoteDisconnected errors because the
server (or an intermediate load balancer) can close the TCP connection at
any time — well before the 5-minute window expires. When that happens,
the next request on the recycled connection hits a dead socket and raises:

('Connection aborted.',
RemoteDisconnected('Remote end closed connection without response'))

This commit introduces a centralized _request() method that all HTTP
methods (get, post, put, patch, delete, post_multipart) now delegate to.
The method applies a reactive retry strategy on top of the existing
proactive refresh:

1. _refresh_if_stale() still runs first as a best-effort preventive measure.
2. If the actual request raises requests.ConnectionError or
   http.client.RemoteDisconnected, the broken session is closed, a fresh
   session is created, and the request is retried exactly once.
3. If the retry also fails, the exception propagates normally — no
   infinite retry loops.

This also consolidates duplicated request logic: each HTTP method no
longer independently calls _refresh_if_stale() and session.<method>(),
reducing the surface for future inconsistencies.

Tests updated to mock session.request (the unified dispatch point) and
four new test cases added covering: ConnectionError retry, RemoteDisconnected
retry, non-retryable errors (e.g. Timeout) pass through, and retry failure
propagation.

Signed-off-by: Guilherme Monteiro de Oliveira <guilherme@monteiroliveira.com>
@monteiroliveira monteiroliveira self-assigned this Apr 17, 2026
@monteiroliveira monteiroliveira added the bug Something isn't working label Apr 17, 2026
@monteiroliveira
Copy link
Copy Markdown
Collaborator Author

Error: Action failed: The process '/opt/hostedtoolcache/sonar-scanner-cli/7.2.0.5079/linux-x64/bin/sonar-scanner' failed with exit code 3

Sonar quebrou..

@monteiroliveira
Copy link
Copy Markdown
Collaborator Author

@lmeilibr tem que dar bump na versão do pyproject

Extract _prepare_and_send and _request_raw so that get_raw benefits
from the same dead-connection retry logic as all other HTTP methods.

Signed-off-by: Guilherme Monteiro de Oliveira <guilherme@monteiroliveira.com>
Cover get_raw happy path, error mapping, ConnectionError retry,
RemoteDisconnected retry, and retry failure propagation. Also
asserts that the prepared URL preserves literal brackets.

Signed-off-by: Guilherme Monteiro de Oliveira <guilherme@monteiroliveira.com>
@lmeilibr lmeilibr merged commit 0252c45 into BCR-CX:main Apr 17, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants