Skip to content

Drop query sessions when balancer bans a node#2208

Open
asmyasnikov wants to merge 10 commits into
masterfrom
purge-sessions-on-banned-node
Open

Drop query sessions when balancer bans a node#2208
asmyasnikov wants to merge 10 commits into
masterfrom
purge-sessions-on-banned-node

Conversation

@asmyasnikov

Copy link
Copy Markdown
Member

Summary

  • Drop idle query pool sessions by NodeID when the driver pessimizes a connection
  • Mark banned nodes so in-use sessions are removed on return to the pool; clear the marker on discovery unban
  • Ban the connection when the session attach stream ends with a transport error

Motivation

After BanOnSessionCreate, native-query still spikes retries during ip-blackhole because long-lived sessions in the pool keep serving requests until they fail through many retry attempts. Purging sessions on ban avoids reusing sessions bound to a dead node.

Test plan

  • go test ./internal/pool/... -run DropIdle
  • go test ./internal/query/... -run BannedNode

Made with Cursor

asmyasnikov and others added 6 commits June 17, 2026 23:33
Pessimize balancer connections when session-create RPCs return UNAVAILABLE or
context.DeadlineExceeded, so client traffic avoids blackholed nodes faster.

Co-authored-by: Cursor <cursoragent@cursor.com>
Purge idle pool sessions by NodeID on conn ban, mark in-use sessions for
removal until discovery unbans the node, and pessimize on attach-stream errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

github.com/ydb-platform/ydb-go-sdk/v3/config

compatible changes

(*Config).NotifyConnAllow: added
(*Config).NotifyConnBan: added
WithOnConnAllow: added
WithOnConnBan: added

summary

Inferred base version: v3.141.0
Suggested version: v3.142.0

@codecov-commenter

codecov-commenter commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.39535% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.71%. Comparing base (44f1152) to head (dc29031).

Files with missing lines Patch % Lines
internal/query/client.go 71.42% 3 Missing and 3 partials ⚠️
driver.go 63.63% 2 Missing and 2 partials ⚠️
config/config.go 85.71% 1 Missing and 1 partial ⚠️
internal/pool/container.go 84.61% 1 Missing and 1 partial ⚠️
internal/pool/pool.go 91.30% 2 Missing ⚠️
Additional details and impacted files
@@                            Coverage Diff                            @@
##           ban-session-create-unreachable-nodes    #2208       +/-   ##
=========================================================================
+ Coverage                                 45.32%   57.71%   +12.39%     
=========================================================================
  Files                                       440      418       -22     
  Lines                                     45321    43155     -2166     
=========================================================================
+ Hits                                      20543    24909     +4366     
+ Misses                                    23722    16033     -7689     
- Partials                                   1056     2213     +1157     
Flag Coverage Δ
go-1.21.x 57.62% <81.39%> (+12.33%) ⬆️
go-1.26.x 57.60% <79.06%> (+12.28%) ⬆️
integration 57.71% <81.39%> (?)
macOS ?
ubuntu 57.71% <81.39%> (+12.39%) ⬆️
unit ?
windows ?
ydb-24.4 57.08% <79.06%> (?)
ydb-edge 57.46% <79.06%> (?)
ydb-latest 57.49% <81.39%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Drop banned in-use sessions in checkItemAndError instead of getItem to
avoid double IsAlive checks; fix struct formatting and add changelog entry.

Co-authored-by: Cursor <cursoragent@cursor.com>

@robot-vibe-db robot-vibe-db Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

Verdict: ❌ 0 critical issues found, 2 major issues found

Critical issues

No critical issues found.

Other findings

  • Major | Medium: Data race on config.onConnBan/onConnAllow — unsynchronized concurrent read/write between config.With() and NotifyConnBan/NotifyConnAllowdriver.go:507, config/config.go:339
  • Major | Medium: onNodeShutdown fires on all Recv() errors (including context cancellation from normal session close), not just transport errors as described in the PR — internal/query/session_core.go:264
  • Minor | Medium: Stale bannedNodes entries if OnConnAllowed is never called (e.g., node permanently removed) — internal/query/client.go:839
  • Minor | Medium: Test coverage for DropIdleByNodeID and banned-node flow does not exercise concurrent access or mixed node IDs — internal/pool/pool_test.go:2571, internal/query/client_banned_node_test.go:9
  • Nit | High: bannedNodes field has inconsistent indentation (one tab instead of two) — internal/query/client.go:63

This review was generated automatically. Critical issues require attention; other findings are advisory.
If this comment was useful, please give it a 👍 — it helps us improve the review bot.

Comment thread driver.go Outdated
Comment thread internal/query/session_core.go Outdated
Comment thread internal/query/client.go Outdated
Comment thread internal/query/client.go
Comment thread internal/query/client_banned_node_test.go
@robot-vibe-db

robot-vibe-db Bot commented Jun 18, 2026

Copy link
Copy Markdown

Full analysis log

Analysis performed by claude, claude-opus-4-6.

asmyasnikov and others added 3 commits June 18, 2026 18:20
Register conn ban callbacks before pool start, skip attach-stream ban on
session close, and extend pool tests for mixed node IDs and banned return.

Co-authored-by: Cursor <cursoragent@cursor.com>
@asmyasnikov

Copy link
Copy Markdown
Member Author

Summary reply to AI review (c346f75):

  • Data race on onConnBan/onConnAllow: fixed — callbacks registered before conn.NewPool.
  • Attach-stream ban on all Recv errors: fixed — skip when session is closing or error is context cancellation.
  • bannedNodes indentation: fixed in 09e0335.
  • Stale bannedNodes entries: accepted as bounded; documented on the field; live nodes cleared via discovery unban.
  • Test coverage: added pool tests for mixed NodeIDs and banned-node return path.

@robot-vibe-db robot-vibe-db Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

Verdict: ✅ No critical issues found

Critical issues

No critical issues found.

Other findings

  • Major | Medium: checkItemAndError reordering changes the behavioral contract of mustDeleteItemFunc — it is now invoked when err == nil, which was previously short-circuited. All current callers handle this correctly, but the change is subtle and undocumented — pool.go:409
  • Minor | High: dropIdleSessionsByNodeID relies on type assertions to *pool.Pool[*Session, Session] rather than an interface method; if the pool implementation changes, idle-session dropping silently stops working — internal/query/client.go:864
  • Minor | Medium: Errors from DropIdleByNodeID are silently discarded; consider tracing/logging for observability — internal/query/client.go:865
  • Nit | High: config.With() godoc says "makes copy of current Config" but actually mutates the receiver in place; the PR relies on this mutation-in-place behavior at driver.go:461 (no return-value assignment). Consider updating the comment to reflect the actual semantics — config/config.go:393

This review was generated automatically. Critical issues require attention; other findings are advisory.
If this comment was useful, please give it a 👍 — it helps us improve the review bot.

Comment thread internal/pool/pool.go
return nil
}

if p.config.mustDeleteItemFunc(item, err) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Major
Confidence: Medium

The reordering of checkItemAndError changes the contract of mustDeleteItemFunc: it is now called even when err == nil, which was previously short-circuited by the early return nil. This means every pool user (including the table service pool at internal/table/client.go:48) now has its mustDeleteItemFunc evaluated on every successful operation, not just on errors.

All current callers handle err == nil correctly (table: err != nil && ... → false; default: !item.IsAlive() → unaffected). However, this is a semantic change to a shared generic component that could surprise future implementors who assume mustDeleteItemFunc is only called on error paths.

Consider documenting this contract change in the function comment or the WithMustDeleteItemFunc godoc.

Comment thread internal/query/client.go
}

func (c *Client) dropIdleSessionsByNodeID(ctx context.Context, nodeID uint32) {
if p, ok := c.explicitSessionPool.(*pool.Pool[*Session, Session]); ok {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Minor
Confidence: High

dropIdleSessionsByNodeID uses type assertions (c.explicitSessionPool.(*pool.Pool[*Session, Session])) rather than relying on an interface method. If sessionPool is ever implemented by a different type (e.g., a mock or wrapper), the assertion silently returns false and idle sessions on banned nodes are never dropped.

Consider either:

  • Adding DropIdleByNodeID(ctx context.Context, nodeID uint32) (int, error) to the sessionPool interface, or
  • Adding a comment explaining this is intentional and why

Comment thread internal/query/client.go

func (c *Client) dropIdleSessionsByNodeID(ctx context.Context, nodeID uint32) {
if p, ok := c.explicitSessionPool.(*pool.Pool[*Session, Session]); ok {
_, _ = p.DropIdleByNodeID(ctx, nodeID)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Minor
Confidence: Medium

Both DropIdleByNodeID calls discard the error with _, _. While the callback has no error-return path, silently swallowing errors (e.g., context cancellation, closed pool) makes debugging harder in production.

Consider at least tracing the error:

if _, err := p.DropIdleByNodeID(ctx, nodeID); err != nil {
    // trace or log
}

@robot-vibe-db

robot-vibe-db Bot commented Jun 18, 2026

Copy link
Copy Markdown

Full analysis log

Analysis performed by claude, claude-opus-4-6.

@asmyasnikov asmyasnikov changed the base branch from ban-session-create-unreachable-nodes to master June 18, 2026 17:20
@asmyasnikov asmyasnikov added SLO and removed SLO labels Jun 18, 2026
@github-actions github-actions Bot removed the SLO label Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants