tests: retry client-routes POST on transient 5xx after decommission - #1019
tests: retry client-routes POST on transient 5xx after decommission#1019mykaul wants to merge 1 commit into
Conversation
A node's REST API can briefly return HTTP 500 for /v2/client-routes right after a decommission/bootstrap while gossip/topology settles. post_client_routes() had no retry, so test_should_survive_full_node_replacement_through_nlb flaked in CI. Retry up to 5 attempts with a 1s backoff, but only on 5xx responses - 4xx or other errors still raise immediately. Also log the response body on failure, which was previously discarded and made past failures hard to diagnose. Fixes scylladb#931 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 53 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: QUIET Plan: Advanced Run ID: 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code Review by Qodo
1. Non-5xx errors receive unnecessary retries
|
| return | ||
| except urllib.error.HTTPError as e: | ||
| body = e.read().decode("utf-8", "replace") | ||
| if e.code >= 500 and attempt < max_attempts: |
There was a problem hiding this comment.
1. Non-5xx errors receive unnecessary retries 🐞 Bug ≡ Correctness
The retry predicate accepts every HTTP error code at or above 500 instead of only codes in the 500–599 range. A non-standard status such as 600 therefore waits and retries four times before failing, contrary to the helper's documented fail-fast behavior for errors outside 5xx.
Agent Prompt
Issue description
The retry condition uses `e.code >= 500`, so HTTP error codes above 599 are retried even though the helper is intended to retry only 5xx responses.
Fix Focus Areas
- tests/integration/standard/test_client_routes.py[258-258]
Recommended Fix
Change the predicate to `500 <= e.code < 600` so only standard 5xx responses are retried; preserve immediate failure for 4xx and other status codes.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| response = urllib.request.urlopen(req) | ||
| log.info("Routes posted successfully (status %d)", response.status) | ||
| return |
There was a problem hiding this comment.
2. Repeated route posts leak http responses 🐞 Bug ☼ Reliability
The success path stores the object returned by urlopen() but returns without closing it, while the new HTTP-error path reads the error body without closing that response either. Calls made repeatedly during route updates can consequently retain HTTP connections or file descriptors until garbage collection, making the test process less reliable under repeated retries and updates.
Agent Prompt
Issue description
`post_client_routes()` does not explicitly close successful responses or `HTTPError` response objects, and the new retry loop can create several response objects per invocation.
Fix Focus Areas
- tests/integration/standard/test_client_routes.py[253-265]
Recommended Fix
Use a context manager around each successful `urlopen()` response and close `HTTPError` objects after reading their bodies, preferably with cleanup in a `finally` block so both retry and terminal-error paths release resources.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Summary
test_should_survive_full_node_replacement_through_nlbdecommissions the original nodes and then immediately POSTs to a surviving node's REST API (/v2/client-routes).decommission()returning doesn't guarantee the surviving node's gossip/topology state and REST subsystem have converged yet, so the POST can transiently hit an HTTP 500 while topology settles — this has been failing intermittently in CI across many unrelated PRs.This is a distinct bug from #948/#949, which was a
TcpProxysocket-lifecycle race in the test's own TCP-forwarding threads (confirmed by reviewing #949's diff — no REST/HTTP code was touched there).Fix
post_client_routes()now retries up to 5 attempts with a 1s backoff, but only for 5xx responses — 4xx or other errors still raise immediately so real bugs aren't masked. Also logs the response body on failure (previously discarded), which the issue flagged as blocking diagnosis of past failures.Considered reusing the existing
wait_until_not_raisedtest helper instead of a dedicated loop, but its bareexcept:swallows any exception (including 4xx) and retries it too, only surfacing whatever the last attempt raises — that would silently retry real client errors instead of failing fast. A loop scoped to 5xx-only is the correct fix, not just a shorter one.Testing
No live Scylla/CCM cluster available to run the integration test end-to-end here. Verified: the file collects cleanly (
pytest tests/integration/standard/test_client_routes.py --collect-only), and a throwaway fake-HTTP-server check confirmed the retry transparently survives 2 transient 500s then succeeds, while a persistent 500 still raises after 5 attempts.Fixes #931
🤖 Generated with Claude Code