fix: SentinelCheckQuorum NOQUORUM dead code + MakeSlaveOfWithPort wrong port - #128
Open
Saremox wants to merge 1 commit into
Open
fix: SentinelCheckQuorum NOQUORUM dead code + MakeSlaveOfWithPort wrong port#128Saremox wants to merge 1 commit into
Saremox wants to merge 1 commit into
Conversation
…ng port SentinelCheckQuorum: real Sentinel's CKQUORUM NOQUORUM outcome comes back as a RESP error, not a successful string reply - so the intended NOQUORUM handling (parsing "(error)"/"NOQUORUM" out of a successful result) could never execute; callers only ever saw the raw driver error. NOQUORUM is now classified from err.Error() directly, restoring the intended "quorum Not available" message and NOQUORUM metrics tag. MakeSlaveOfWithPort(ip, masterIP, masterPort, password) connected to the *target* redis instance at (ip, masterPort) - using the master's port to reach the target, with no parameter for the target's own port. This only worked because every caller except SetExternalMasterOnAll happens to pass the same port for target and master (both come from this RedisFailover's own spec.redis.port). SetExternalMasterOnAll's externally-supplied bootstrap master port can genuinely differ, in which case the client silently connected to the wrong instance (or, when target and master share an IP, issued SLAVEOF to the master itself) instead of failing loudly. MakeSlaveOfWithPort now takes an explicit port for the target, separate from masterPort; all call sites, the mock, and MakeSlaveOf updated accordingly. Both found and confirmed against real Redis/Sentinel 7.0.15 while writing coverage tests for this file.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two real bugs found and fixed in
service/redis/client.go, both confirmed against real Redis/Sentinel 7.0.15 (and cross-checked against Valkey 7.2.12 in the investigation that surfaced them).1.
SentinelCheckQuorum's NOQUORUM handling was dead codeReal Sentinel's
SENTINEL CKQUORUMreply for the NOQUORUM case comes back as a genuine RESP error reply, not a successful string reply whose text happens to start with"(error)". Since go-redis'sCkQuorumsurfaces that ascmd.Err(), the function'sif err != nil { return err }branch fired immediately — the subsequent string-parsing code that checked forstatus == "(error)" && quorum == "NOQUORUM"could never execute, sinceresis only non-empty whenerris nil. Callers still correctly saw a non-nil error (the raw driver error happens to mention NOQUORUM too), but the intended"quorum Not available"message andNOQUORUMmetrics tag never fired.Fix: NOQUORUM is now classified directly from
err.Error()(which real Sentinel prefixes with"NOQUORUM ...") before the now-simplified success-path parsing. Verified against a real Sentinel process —TestSentinelCheckQuorum_NoQuorumnow asserts the exact restored message.2.
MakeSlaveOfWithPortconnected to the target using the master's portMakeSlaveOfWithPort(ip, masterIP, masterPort, password)dialed the target Redis instance atnet.JoinHostPort(ip, masterPort)— using the master's port to reach the target, with no parameter for the target's own port. This only worked by coincidence: every caller exceptSetExternalMasterOnAllpasses the same port for both target and master (both come fromspec.redis.porton the same RedisFailover).SetExternalMasterOnAll's externally-supplied Bootstrapping master port (spec.bootstrapNode.port) can genuinely differ fromspec.redis.port— in which case the client silently connected to the wrong port (or, if target and master share an IP, ended up issuingSLAVEOFto the master itself, which Redis accepts without error) instead of failing loudly.Fix:
MakeSlaveOfWithPortnow takes an explicitportfor the target, separate frommasterPort. Updated the interface, all four call sites inheal.go(SetOldestAsMaster,SetMasterOnAll,SetExternalMasterOnAll,PromoteBestReplica), theMakeSlaveOfconvenience wrapper, the generated mock, and all affected tests. Verified against two real, independently-addressable Redis instances on different ports —TestMakeSlaveOfWithPort_MismatchedTargetPortnow asserts the target is correctly reconfigured and the master is left untouched.Test plan
go build ./...go vet ./...go test ./...(full repo, including real redis-server/sentinel subprocess tests, ~17s)golangci-lint run --no-config ./service/redis/... ./operator/redisfailover/... ./mocks/...— 0 issuesgofmt -lon all changed files — cleanGenerated by Claude Code