Skip to content

CI: client-routes full node replacement test can fail with HTTP 500 after decommission #931

Description

@dkropachev

Failure

Integration test flake seen in PR #913:

Failed test:

tests/integration/standard/test_client_routes.py::TestFullNodeReplacementThroughNlb::test_should_survive_full_node_replacement_through_nlb

Error:

urllib.error.HTTPError: HTTP Error 500: Internal Server Error

Observed sequence

The failure happened during Stage 4, while decommissioning original nodes behind the NLB emulator.

Relevant CI log sequence:

14:35:32.132 Posting 6 routes to http://127.0.0.1:10000/v2/client-routes -> 200
14:35:40.138 Stage 4: Decommissioning original nodes [1, 2, 3]
14:35:46.982 Posting 5 routes to http://127.0.0.3:10000/v2/client-routes -> 200
14:35:47.030 Node 1 decommissioned, 5 nodes still via NLB
14:35:47.030 Decommissioning node 2
14:35:49.371 Posting 4 routes to http://127.0.0.3:10000/v2/client-routes
14:35:50.229 pytest begins teardown after HTTP 500

The failing POST is from:

tests/integration/standard/test_client_routes.py:1247

The helper uses urllib.request.urlopen(req) directly at:

tests/integration/standard/test_client_routes.py:366

Because urllib.error.HTTPError is not caught and its response body is not logged, the CI output does not include the Scylla-side reason for the 500.

Race hypothesis

The test appears to have a topology-change race window. In the decommission loop it currently:

  1. calls get_node(node_id).decommission()
  2. removes the node from the NLB emulator
  3. removes the host id from the route map
  4. immediately POSTs the updated route set to /v2/client-routes
  5. only afterwards waits for driver metadata/query stability

So the route update can hit a surviving node while Scylla is still settling after the decommission. In this failure it posted to 127.0.0.3:10000 immediately after node2 removal and got a transient-looking 500.

Local reproduction attempt

Targeted reruns of the exact PR merge did not reproduce locally:

SCYLLA_VERSION=release:2026.1 EVENT_LOOP_MANAGER=asyncio PROTOCOL_VERSION=4 \
  uv run pytest -q -s tests/integration/standard/test_client_routes.py::TestFullNodeReplacementThroughNlb::test_should_survive_full_node_replacement_through_nlb

Results:

run 1: passed, 126.60s
run 2: passed, 60.08s
run 3: passed, 91.11s

Local Python was 3.13.5, not CI's 3.13.14.

Even on passing local runs, Scylla emitted topology/rpc noise during this flow, for example:

storage_service - Failed to complete splitting of table ... Read barrier requested by a node outside of the configuration ... retrying after 5000ms
rpc - server connection dropped: Semaphore broken

That supports this being timing-sensitive topology churn, not a deterministic driver failure.

Artifacts

There are no uploaded artifacts for the run:

{"total_count":0,"artifacts":[]}

The workflow also does not have an actions/upload-artifact step, so no cluster logs are available beyond the job log.

Suggested fix

Make this test more robust and diagnosable:

  • catch urllib.error.HTTPError in post_client_routes() and log/read the response body
  • retry bounded 5xx responses for /v2/client-routes during this replacement test
  • consider waiting for topology/query stability before posting updated routes after each decommission, or choose a known stable surviving/new node for the REST POST

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions