Conversation
Signed-off-by: Mei <MTx1534572236@outlook.com>
| if !ok { | ||
| return true | ||
| } | ||
| if k == addr || strings.HasSuffix(k, suffix) { |
There was a problem hiding this comment.
Concurrency caveat (informational, not blocking): Range deletes matching keys, but a concurrent GetWorkerConn(addr) for the same address whose LoadOrStore lands after this Range passes that key will re-cache a brand-new pool that this call never sees or closes — so "close on node down" is best-effort under in-flight traffic, not a hard guarantee. It is self-healing, since the periodic checkWorkerConn sweep reclaims idle pools (ref == 0 && expired), so a leaked pool is eventually cleaned up. If a strict guarantee were wanted, the close path would need to coordinate with GetWorkerConn (e.g. a per-address mutex or a tombstone check after Range).
| pool3 := &mockPool{} | ||
| poolOther := &mockPool{} | ||
|
|
||
| connPool = &workerGrpcConnPool{ |
There was a problem hiding this comment.
Minor: these tests mutate the package-global connPool and never restore it, so correctness depends on execution order within this file (Go runs tests in file order and this is currently the only test file in the package, so it works today). It's fragile: if another _test.go file in this package is added later and assumes an initialized pool (e.g. via Init), ordering breaks. Consider saving the prior connPool value and restoring it with t.Cleanup, or initializing the pool in a TestMain. Also note the mock Get() returns a nil grpcpool.Conn, so TestGetWorkerConnCached exercises the cache-hit branch but doesn't validate a usable connection — the "100% coverage" claim in the description overstates the GetWorkerConn create-new-pool path, which is untested.
Review: fix(grpcconn): match full and prefixed keys in CloseWorkerConn (#1585)AI-generated review — no human approval implied. VerdictApprove with minor comments. The change correctly fixes a real bug: I verified against the base tree: all Findings
Notes
|
…kerConn Signed-off-by: Mei <MTx1534572236@outlook.com>
| if !ok { | ||
| return true | ||
| } | ||
| if k == addr || strings.HasSuffix(k, suffix) { |
There was a problem hiding this comment.
The whole match now rests on strings.HasSuffix(k, "+"+addr) — i.e., on the + separator and on the exact address string format. For the current callers this is safe: every key is UA + "+" + addr where addr comes from GetCubeletAddr(HostIP()) (ip:port), and no two valid ip:port strings are proper suffixes of one another (the + delimiter anchors the match). Two notes:
- The
k == addrexact-match branch is actually unreachable today —GetWorkerConnalways storesUA + "+" + addr(even with an empty UA the key is+addr), never a bareaddr. It's harmless defensive code, but it's misleading: it suggests bare-addr keys exist when they don't. - Because the identity lives in the key as a string-suffix convention, any future change to the key format (e.g., a UA containing
+, or a hostname address that is a suffix of another) would silently over- or under-close pools. Since the address is the stable entity and the UA is just per-caller, keying the cache byaddralone (holding the UA in the value) — or storing the address in the value and scanning that — would make closure robust to format changes rather than depending on a delimiter.
| if k == addr || strings.HasSuffix(k, suffix) { | ||
| connPool.cache.Delete(key) | ||
| if cp != nil { | ||
| _ = cp.(grpcpool.Pool).Close() |
There was a problem hiding this comment.
Question (not a regression): Pool.Close() immediately sets current = 0 and resets/closes all underlying grpc.ClientConns, so any in-flight RPC on these connections is aborted. CloseWorkerConn is invoked from both downNodeCache (node down — force-close is clearly right, the node is unreachable) and delNodeCache (node removal), where in-flight operations might still be able to complete. grpcpool.Pool exposes GracefulStop(maxWaitTime) for exactly this drain-then-close case. Note the existing checkWorkerConn cleanup path also uses Close(), so this is consistent with current behavior — flagging only so the choice is deliberate. A stale Get() racing with this close will surface as ErrClosed/ErrorCode_ConnHostFailed; that window is inherent to the lock-free design and pre-existing.
| t.Fatalf("expected pool3 to be closed") | ||
| } | ||
|
|
||
| // Other address should remain intact |
There was a problem hiding this comment.
The negative case here uses a different IP with the same port — it does not exercise the dangerous class of near-miss keys, i.e. one address being a proper suffix of another stored key's address. The entire fix rests on strings.HasSuffix, so it's worth pinning down that the + delimiter prevents over-closing. Suggest adding a case where the closed addr is a prefix of another cached addr with the same IP but a longer/different port — e.g. cache "uaX+" + "1.2.3.4:12345", call CloseWorkerConn("1.2.3.4:1234"), and assert the ...:12345 pool is untouched (HasSuffix correctly returns false because the key ends in 5). That locks in the delimiter behavior against future key-format changes.
Summary
Fixes #1584
In
CubeMaster/pkg/cubelet/grpcconn/worker_conn.go,GetWorkerConnstores connection pools underua + "+" + addr. However,CloseWorkerConn(addr)previously performed a direct lookup with the bareaddrstring (connPool.cache.Load(addr)).Because the keys did not match,
CloseWorkerConnwas a silent no-op. Calls fromnode_cache(node_cache.go:220/240) upon node down / deletion failed to immediately close active gRPC connections for the removed node.Changes
CloseWorkerConn(addr string)to scanconnPool.cacheusingRangeand match entries wherekey == addrorstrings.HasSuffix(key, "+"+addr).connPool.cacheand close the corresponding connection pools (Pool.Close()).if connPool == nil { return }nil guard.CubeMaster/pkg/cubelet/grpcconn/worker_conn_test.gocovering matching, nil-pool handling, and uninitialized pool errors (100% target function test coverage).Verification
go test -v -cover ./pkg/cubelet/grpcconn/...passes cleanly.gofmt -wverified.