xds/resolver: ensure OnCommitted is invoked on early stream creation failure to prune unreferenced clusters. - #9140
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #9140 +/- ##
==========================================
- Coverage 83.33% 83.09% -0.25%
==========================================
Files 420 422 +2
Lines 34028 34862 +834
==========================================
+ Hits 28358 28969 +611
- Misses 4253 4395 +142
- Partials 1417 1498 +81
🚀 New features to boost your workflow:
|
| } | ||
|
|
||
| func (icc *interceptingClientConn) UpdateState(state resolver.State) error { | ||
| return icc.ClientConn.UpdateState(state) |
There was a problem hiding this comment.
Nit : we can remove this function since clientconn is already embedded and this is just passthrough function.
| // been prematurely removed. | ||
| select { | ||
| case js := <-jsonCh: | ||
| compareJSONConfigs(t, js, wantServiceConfig(clusterA, clusterB)) |
There was a problem hiding this comment.
Nit: I think we should return error from here , since config update is not expected.
| } | ||
|
|
||
| // Create an intercepting resolver builder. | ||
| jsonCh := make(chan string, 10) |
There was a problem hiding this comment.
Nit: Do we need a channel of size 10 ?
mbissa
left a comment
There was a problem hiding this comment.
LGTM. Validated the approach and test scenarios solve the usecases we need.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the management of cluster and plugin reference counts during RPC execution, ensuring that the OnCommitted callback is idempotent and executed on stream termination even if stream creation fails early. It also introduces comprehensive end-to-end tests for delayed cluster removal. Feedback on the changes points out a potential source of test flakiness in the new end-to-end test due to non-deterministic channel selection when unblocking concurrent RPCs, and suggests a robust way to handle either RPC finishing first.
| } | ||
|
|
||
| // Create an intercepting resolver builder. | ||
| jsonCh := make(chan string, 4) |
There was a problem hiding this comment.
Why do we need a buffer of 4 here?
There was a problem hiding this comment.
We can go with a buffer of 3 here.
There was a problem hiding this comment.
We only need a buffer of 1. The test is reading items out of the channel before the next item is enqueued. So, I don't understand why it needs to have a buffer of anything greater than 1.
There was a problem hiding this comment.
This applies to other places where this channel is defined as well.
| } | ||
|
|
||
| // Create an intercepting resolver builder. | ||
| jsonCh := make(chan string, 4) |
There was a problem hiding this comment.
We only need a buffer of 1. The test is reading items out of the channel before the next item is enqueued. So, I don't understand why it needs to have a buffer of anything greater than 1.
| } | ||
|
|
||
| // Create an intercepting resolver builder. | ||
| jsonCh := make(chan string, 4) |
There was a problem hiding this comment.
This applies to other places where this channel is defined as well.
|
Please handle the minor nit in the test and please add a release note before merging. |
This PR handles the cluster ref count leaks in case of stream creation failure.
When an xDS ConfigSelector selects a cluster or cluster specifier plugin for an RPC, it increments the cluster's reference count to keep the cluster active in the Service Config while the RPC is in flight. Previously, if stream creation failed early (e.g., aborted inside an xDS HTTP filter or interceptor before the stream was committed), or in OnCommitted would never be called, leaving the cluster reference count permanently elevated and preventing old/removed clusters from being pruned from the Service Config.
This PR ensures OnCommitted is reliably invoked even when stream creation fails early, and makes the callback idempotent so cluster reference counts are decremented exactly once per RPC.
Key Changes
stream.go (newClientStream):
internal/xds/resolver/serviceconfig.go (configSelector.SelectConfig):
RELEASE NOTES: