Skip to content

test(redis): scan a cluster node by node again, and ask the server which it is - #2348

Merged
giokur merged 4 commits into
mainfrom
test/redis-cluster-scan-and-detect
Sep 23, 2026
Merged

giokur merged 4 commits into
mainfrom
test/redis-cluster-scan-and-detect

Conversation

@giokur

@giokur giokur commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

The password-reset lookup broke on qa, and the same code path is what the production tenant report uses to
rotate its own credentials.

What broke

Reading the password-reset token from Redis failed
  redis.clients.jedis.exceptions.JedisClusterOperationException: Could not initialize cluster slots cache

#2207 replaced a client that never consulted cluster topology with JedisCluster, which must run
CLUSTER SLOTS first:

before new Jedis(node) per seed, SCAN each node directly
after new JedisCluster(nodes, config) → topology discovery → fails from the test pod

Verify that user can reset password passed on 09-18, 09-21, 09-22 and at 06:09 on 09-23; it failed at
11:24 on 09-23, the first run on a build containing #2207.

Why it matters beyond the test

ReportCredentialRotator binds its token source to Redis::getResetToken. Rotation runs before any
tenant is collected, and its failure path is fatal, so the production tenant report would post nothing
four times a day — and the account is left mid-rotation, a state the rotator's own comment says a re-run
cannot repair. Production runs promoted tags (values-prod.yaml: 1.0.69), so the exposure arrives with
the next promotion rather than now.

The change

The cluster path scans node by node again. SCAN only ever reports the keys of the node answering it,
so the seeds are walked one at a time, as before #2207. No topology discovery, because nothing here needs
it.

The Memorystore path is untouched — single JedisPooled, TLS from the published CA, AUTH — exactly as
#2207 built it.

Which topology to use is now asked, not configured. SaaS Redis is migrating to Memorystore for Valkey
(one node, cluster mode disabled) one environment at a time, so the answer differs per environment and
changes as the migration proceeds. CLUSTER INFO is answered by both topologies, so a single round trip
settles it and the result is remembered for the JVM. An environment migrates without anyone editing
config; RedisConfig.setCluster(...) still pins it as an escape hatch, and a probe that cannot connect
assumes a cluster — what every environment but dev is today.

Compiles. Worth noting the runner's TestLibRedisBridge currently calls setCluster unconditionally from
a defaulted property, so detection only takes over once that is changed to pass through only when the
property is set — a separate saas-shared change. Until then this PR still fixes qa, because the pinned
value there is true and the cluster path works again.


🤖 Generated with Claude Code

giokur and others added 2 commits September 23, 2026 14:51
…ich it is

The password-reset lookup stopped working on qa:

  Reading the password-reset token from Redis failed
  JedisClusterOperationException: Could not initialize cluster slots cache

#2207 replaced a client that never needed cluster topology with JedisCluster,
which must run CLUSTER SLOTS before anything else. The advertised node addresses
are not reachable from the test pod, so discovery fails and the lookup returns
null — the all-tests run of 2026-09-23 11:24 failed "Verify that user can reset
password" on it, after five clean runs.

This is not only a test: ReportCredentialRotator binds its token source to
Redis::getResetToken, and rotation runs before any tenant is collected, so the
production tenant report would post nothing four times a day and leave the
account half-rotated — a state its own comment says a re-run cannot repair. Prod
is on promoted tags today, so the exposure arrives with the next promotion.

SCAN is per-node in a cluster, so the seeds are walked one at a time again, as
they were before #2207. The single-client path stays exactly as #2207 built it
for Memorystore, along with its TLS and AUTH.

Which topology to use is now asked rather than configured. SaaS Redis is moving
to Memorystore for Valkey — one node, cluster mode disabled — one environment at
a time, so the answer differs per environment and changes as the migration
proceeds. CLUSTER INFO is answered by both, so one round trip settles it, the
result is remembered for the JVM, and an environment migrates without anyone
editing config. RedisConfig.setCluster still pins it where someone wants to, and
a probe that cannot connect assumes a cluster, which is what every environment
but dev is today.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every seed throwing and every seed answering with nothing both produce null, and
the caller polls on null until its timeout. Only one of those is worth waking
someone for: ReportCredentialRotator has already requested the reset by then, so
a token that exists but is unreachable leaves the tenant-report account
half-rotated — the state its own comment says a re-run cannot repair.

Counts the seeds that were actually scanned and warns when that is none.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@giokur
giokur marked this pull request as ready for review September 23, 2026 14:00
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

🦩 Flamingo Code Review

3 finding(s) — 1 action required · 2 recommended · 0 informational

Mode: advisory · Rules cited: OFJAVA-013 · 2 defect(s) outside any rule

Inline comments: 3 new


Need another pass? Commits pushed after this review are not reviewed automatically.

  • Review the new commits — the commits added since this review
  • Review the whole diff again — ignoring what was already reviewed

Prefer typing? Comment @flamingo-review, or @flamingo-review full. To review every push on this pull request, add the flamingo-review-always label.

React 👍/👎 on inline comments to teach the reviewer.

Started 2026-09-23 14:00 UTC · updated 2026-09-23 14:01 UTC · workflow run

Review on #2348: a probe that fails caches its guess for the life of the JVM.

The guess itself stays - assuming a cluster is right for every environment but
dev, and it keeps behaviour unchanged when the probe is the broken part - but it
is no longer remembered. probeCluster returns null for "the server did not say",
clusterMode answers true for that one lookup, and the next lookup asks again.
This pod runs for days between rollouts, and one dropped SYN on the egress NAT
is enough to lose a probe; pinning a guess on that for days is the failure the
detection was meant to remove, not add.

Also drops the auto-unboxing return of the field inside the synchronized block
in favour of a local, now that probeCluster really can return null.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@giokur
giokur enabled auto-merge (squash) September 23, 2026 14:18
@giokur
giokur merged commit 5fc3a07 into main Sep 23, 2026
12 of 13 checks passed
@giokur
giokur deleted the test/redis-cluster-scan-and-detect branch September 23, 2026 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants