Skip to content

odcds: add inactivity timeout for removal of discovered clusters#46069

Open
akonradi wants to merge 7 commits into
envoyproxy:mainfrom
akonradi:odcds-inactivity
Open

odcds: add inactivity timeout for removal of discovered clusters#46069
akonradi wants to merge 7 commits into
envoyproxy:mainfrom
akonradi:odcds-inactivity

Conversation

@akonradi

@akonradi akonradi commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Commit Message:
Add a configurable timeout to the HTTP ODCDS filter that, when enabled, is attached to discovered clusters. When a cluster discovered via ODCDS hasn't had any streams through it for the timeout interval it becomes eligible for automatic cleanup (though the cleanup sweep might not get to it for up to 2x the timeout). Cleanup removes the cluster and its subscription; if the cluster is needed again for a later request the ODCDS filter will rediscover it, like new. The net effect is lazy garbage collection: ODCDS clusters can stop being a source of unbounded resource growth past the point where they're useful.

Additional Description:
Generated with AI tooling and self-review. Low risk because the feature is disabled by default.

Risk Level: low
Testing: added unit and integration tests, ran existing tests
Docs Changes: new field documented
Release Notes: added to new_features
Platform Specific Features: n/a
[Optional API Considerations:]
The default value disables the feature.

akonradi added 4 commits July 9, 2026 20:18
Signed-off-by: Alex Bakon <abakon@netflix.com>
Signed-off-by: Alex Bakon <abakon@netflix.com>
Signed-off-by: Alex Bakon <abakon@netflix.com>
Signed-off-by: Alex Bakon <abakon@netflix.com>
@repokitteh-read-only

Copy link
Copy Markdown

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @wbpcode
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #46069 was opened by akonradi.

see: more, trace.

@akonradi akonradi marked this pull request as draft July 9, 2026 21:07
Signed-off-by: Alex Bakon <abakon@netflix.com>
@akonradi akonradi marked this pull request as ready for review July 9, 2026 21:30
Signed-off-by: Alex Bakon <abakon@netflix.com>

@wbpcode wbpcode left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

/lgtm api

// A cluster that has been idle for this long will be subject to automatic removal.
// An idle cluster is one that has no streams to any of its endpoints.
// Inactivity detection is disabled if this value is zero or unset.
google.protobuf.Duration cluster_inactivity_timeout = 4 [(validate.rules).duration = {gte {}}];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

After a rethink, may be call the cluster_idle_timeout to consistency with our lots of other _idle_timeout.

And I am think should this API be part of OnDemand or this OnDemandCds

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Renamed to use "idle" vs "inactivity".

Moving out of the shared OnDemandCds into the filter-specific OnDemand would mean that the route version wouldn't have the same behavior. What would be the benefit of that?

Comment on lines +19 to +31
// Reads a cluster's live active-stream and cumulative-request counts. Returns nullopt if the
// cluster is no longer an active cluster in the manager.
std::optional<OdCdsClusterInactivityTimeout::ClusterActivityStats>
sampleClusterActivity(const ClusterManager& cm, absl::string_view cluster_name) {
const OptRef<const Cluster> cluster = cm.getActiveCluster(cluster_name);
if (!cluster.has_value()) {
return std::nullopt;
}
const ClusterInfoConstSharedPtr info = cluster->info();
return OdCdsClusterInactivityTimeout::ClusterActivityStats{
.active_rq = info->trafficStats()->upstream_rq_active_.value(),
.total_rq = info->trafficStats()->upstream_rq_total_.value(),
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we take the contention into account, seems this is is not good enough to detect a expired cluster? cc @kyessenov

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is there a specific scenario you're imagining where this wouldn't work?

@wbpcode wbpcode left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the contrition. Refreshed my comments.

@wbpcode

wbpcode commented Jul 12, 2026

Copy link
Copy Markdown
Member

and ping codeowner cc @kyessenov

Signed-off-by: Alex Bakon <abakon@netflix.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants