ops(OPS67): retry com backoff nos fetchs do forgejo-api #84

Merged
fsolla merged 1 commit from OPS67-forgejo-retry-com-backoff-nos-fetchs-do-forgejo-api-fe into main 2026-08-19 13:28:38 +00:00
Owner

Closes #73

OPS67 — retry com backoff nos fetchs do forgejo-api. Um fetch failed transitório (rede/DNS/reset — o sintoma que matava o run do safety net agent-pr-ready-automerge.yml no meio da espera de checks) agora retenta dentro do request() de scripts/lib/forgejo-api.mjs — o choke point único do transporte Forgejo (19 call sites: safety net, claim/status, issue-transition, branch-protection, pool, worktree), zero-dep mantido.

Política (aprovada no gate humano, impl plan docs/plans/ops67-forgejo-api-retry-backoff-impl.md):

  • Fetch reject de rede → retenta em qualquer método (inclusive leitura de body interrompida no meio — mesma classe de falha — em GET; body-drop em escrita falha fail-closed).
  • 5xx (502/503/504) → retenta só em GET (protege o poll de 45 min do waitForChecks contra blip do Cloudflare; body do 5xx cancelado antes do retry para liberar o socket). Escrita com 5xx falha na hora — sem risco de duplicar efeitos colaterais.
  • 4xx → nunca retenta; falha permanente continua exit 1 com a mesma mensagem (contrato dos callers intacto).
  • Backoff exponential: 3 retries, base 300 ms ×2, jitter ±20%, console.warn pt-BR por retry (tentativa N/4); validação retries >= 0/backoffMs >= 0.
  • Opções flat no createApi (retries, backoffMs, jitter, sleepImpl) espelhando o fetchImpl injetável — defaults preservam o comportamento de todos os callers; testes determinísticos (sem espera real).

Testes: 12 specs novas em forgejoApi.unit.spec.ts (rede GET/POST → sucesso, body-drop GET retenta + POST fail-closed, exaustão de rede/5xx, retries: 0, backoff exponencial [100, 200, 400], jitter ±20% com Math.random pinado, 4xx sem retry, 5xx-GET retry/exaustão, 5xx-POST sem retry) + pin no spec 403 existente. Verificação: unit 2403 verdes; lint/format/typecheck/knip/cycles verdes.

/simplify absorvido: body-drop em GET retentável (P2), cancel do body do 5xx (P2), código morto removido + validação de parâmetros, closure retryAfter única, describe em inglês, restore de mocks, 5 specs de borda adicionadas. Sem migration/access/Consent/UI/DB.

Changelog: docs/changelog/2026-08-19-ops67.md.

Closes #73 **OPS67 — retry com backoff nos fetchs do forgejo-api.** Um `fetch failed` transitório (rede/DNS/reset — o sintoma que matava o run do safety net `agent-pr-ready-automerge.yml` no meio da espera de checks) agora retenta dentro do `request()` de `scripts/lib/forgejo-api.mjs` — o choke point único do transporte Forgejo (19 call sites: safety net, claim/status, issue-transition, branch-protection, pool, worktree), zero-dep mantido. **Política (aprovada no gate humano, impl plan `docs/plans/ops67-forgejo-api-retry-backoff-impl.md`):** - **Fetch reject de rede → retenta em qualquer método** (inclusive leitura de body interrompida no meio — mesma classe de falha — em GET; body-drop em escrita falha fail-closed). - **5xx (502/503/504) → retenta só em GET** (protege o poll de 45 min do `waitForChecks` contra blip do Cloudflare; body do 5xx cancelado antes do retry para liberar o socket). Escrita com 5xx falha na hora — sem risco de duplicar efeitos colaterais. - **4xx → nunca retenta**; falha permanente continua exit 1 com a mesma mensagem (contrato dos callers intacto). - Backoff exponential: 3 retries, base 300 ms ×2, jitter ±20%, `console.warn` pt-BR por retry (`tentativa N/4`); validação `retries >= 0`/`backoffMs >= 0`. - Opções flat no `createApi` (`retries`, `backoffMs`, `jitter`, `sleepImpl`) espelhando o `fetchImpl` injetável — defaults preservam o comportamento de todos os callers; testes determinísticos (sem espera real). **Testes:** 12 specs novas em `forgejoApi.unit.spec.ts` (rede GET/POST → sucesso, body-drop GET retenta + POST fail-closed, exaustão de rede/5xx, `retries: 0`, backoff exponencial [100, 200, 400], jitter ±20% com `Math.random` pinado, 4xx sem retry, 5xx-GET retry/exaustão, 5xx-POST sem retry) + pin no spec 403 existente. Verificação: unit 2403 verdes; lint/format/typecheck/knip/cycles verdes. **/simplify absorvido:** body-drop em GET retentável (P2), cancel do body do 5xx (P2), código morto removido + validação de parâmetros, closure `retryAfter` única, `describe` em inglês, restore de mocks, 5 specs de borda adicionadas. Sem migration/access/Consent/UI/DB. Changelog: `docs/changelog/2026-08-19-ops67.md`.
fsolla added 1 commit 2026-08-19 13:25:01 +00:00
ops(OPS67): retry com backoff nos fetchs do forgejo-api
All checks were successful
CI (PR) / checks (pull_request) Successful in 3m19s
PR Ready + auto-merge / ready-automerge (pull_request) Successful in 3m36s
Promote plan-issue Related on main merge / plan-issue-ready (pull_request) Has been skipped
Main merge flips claimed issues to done + in-prod / issue-done (pull_request) Successful in 27s
99cadc068e
Um fetch failed transitorio (rede/DNS/reset) matava o run do safety net
(agent-pr-ready-automerge) no meio da espera de checks. Retry no request()
do cliente: fetch reject retenta em qualquer metodo; body-drop em GET
retenta; 5xx (502/503/504) retenta so em GET (body cancelado antes do
retry); 4xx e body-drop em escrita falham fail-closed. 3 retries, base
300ms x2, jitter +-20%, console.warn pt-BR por retry; opcoes flat no
createApi (retries/backoffMs/jitter/sleepImpl). 12 specs unit novas.
fsolla merged commit cc6149191b into main 2026-08-19 13:28:38 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: fsolla/teqo#84
No description provided.