Skip to content

A50: Exclude locally-initiated client cancellations from Call Counter (#12923) - #558

Open
AgraVator wants to merge 5 commits into
grpc:masterfrom
AgraVator:a50-client-cancellations
Open

A50: Exclude locally-initiated client cancellations from Call Counter (#12923)#558
AgraVator wants to merge 5 commits into
grpc:masterfrom
AgraVator:a50-client-cancellations

Conversation

@AgraVator

@AgraVator AgraVator commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Clarifies gRFC A50 (A50-xds-outlier-detection.md) to explicitly define that locally-initiated client-side cancellations MUST be excluded from the Outlier Detection Call Counter (successCount and failureCount), following the cross-language discussion consensus.

Key Clarifications

  1. Picker Counting: Excludes locally-initiated client-side cancellations (hedging cancellations, application CANCELLED, and DEADLINE_EXCEEDED) from counter increments on call completion.
  2. Call Counter: Clarifies that active buckets track successCount and failureCount, omitting locally cancelled calls.
  3. Rationale: Explains that locally-initiated client-side cancellations (including DEADLINE_EXCEEDED, which is treated as a client-side cancellation from first principles and for implementation simplicity) are excluded from outlier detection counting to align with Envoy's resetStream() behavior and prevent false-positive ejections during hedging.

Related Work

Comment thread A50-xds-outlier-detection.md Outdated
@AgraVator
AgraVator requested a review from kannanjgithub August 3, 2026 07:06
@ejona86
ejona86 requested a review from murgatroid99 August 7, 2026 16:15
When the child policy asks for a subchannel, the `outlier_detection` will wrap the subchannel with a wrapper (see [Subchannel Wrapper section](#subchannel-wrapper)). Then, the subchannel wrapper will be added to the list in the map entry for its address, if that map entry exists. If there is no map entry, or if the subchannel is created with multiple addresses, the subchannel will be ignored for outlier detection. If that address is currently ejected, that subchannel wrapper's `eject` method will be called.

The `outlier_detection` LB policy will provide a picker that delegates to the child policy's picker, and when the request finishes, increment the corresponding counter in the map entry referenced by the subchannel wrapper that was picked. If both the `success_rate_ejection` and `failure_percentage_ejection` fields are unset in the configuration, the picker should not do that counting.
The `outlier_detection` LB policy will provide a picker that delegates to the child policy's picker, and when the request finishes, increment the corresponding counter in the map entry referenced by the subchannel wrapper that was picked. Locally-initiated client-side cancellations (hedging cancellations, application `CANCELLED`, and `DEADLINE_EXCEEDED`) MUST be excluded from `successCount` and `failureCount`. If both the `success_rate_ejection` and `failure_percentage_ejection` fields are unset in the configuration, the picker should not do that counting.

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.

application CANCELLED and DEADLINE_EXCEEDED shouldn't be in all-upper-case, as it makes it seem like this is based on the status code. Just describe them. ("application cancellation, and deadline exceeded")

When the child policy asks for a subchannel, the `outlier_detection` will wrap the subchannel with a wrapper (see [Subchannel Wrapper section](#subchannel-wrapper)). Then, the subchannel wrapper will be added to the list in the map entry for its address, if that map entry exists. If there is no map entry, or if the subchannel is created with multiple addresses, the subchannel will be ignored for outlier detection. If that address is currently ejected, that subchannel wrapper's `eject` method will be called.

The `outlier_detection` LB policy will provide a picker that delegates to the child policy's picker, and when the request finishes, increment the corresponding counter in the map entry referenced by the subchannel wrapper that was picked. If both the `success_rate_ejection` and `failure_percentage_ejection` fields are unset in the configuration, the picker should not do that counting.
The `outlier_detection` LB policy will provide a picker that delegates to the child policy's picker, and when the request finishes, increment the corresponding counter in the map entry referenced by the subchannel wrapper that was picked. Locally-initiated client-side cancellations (hedging cancellations, application `CANCELLED`, and `DEADLINE_EXCEEDED`) MUST be excluded from `successCount` and `failureCount`. If both the `success_rate_ejection` and `failure_percentage_ejection` fields are unset in the configuration, the picker should not do that counting.

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.

Don't do MUST. This document is not using that style.

When the child policy asks for a subchannel, the `outlier_detection` will wrap the subchannel with a wrapper (see [Subchannel Wrapper section](#subchannel-wrapper)). Then, the subchannel wrapper will be added to the list in the map entry for its address, if that map entry exists. If there is no map entry, or if the subchannel is created with multiple addresses, the subchannel will be ignored for outlier detection. If that address is currently ejected, that subchannel wrapper's `eject` method will be called.

The `outlier_detection` LB policy will provide a picker that delegates to the child policy's picker, and when the request finishes, increment the corresponding counter in the map entry referenced by the subchannel wrapper that was picked. If both the `success_rate_ejection` and `failure_percentage_ejection` fields are unset in the configuration, the picker should not do that counting.
The `outlier_detection` LB policy will provide a picker that delegates to the child policy's picker, and when the request finishes, increment the corresponding counter in the map entry referenced by the subchannel wrapper that was picked. Locally-initiated client-side cancellations (hedging cancellations, application `CANCELLED`, and `DEADLINE_EXCEEDED`) MUST be excluded from `successCount` and `failureCount`. If both the `success_rate_ejection` and `failure_percentage_ejection` fields are unset in the configuration, the picker should not do that counting.

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.

Referencing successCount and failureCount before they are defined is confusing.

I think we could avoid the change in this paragraph. The Call Counter section is the one that looks to be really defining this. Maybe we can make this section more generic so it won't be assumed to be thorough by s/increment the corresponding counter/updates the counter/. Michael may have a preference.

At that point I think we remove defining successCount and failureCount as variables, and remove the reference to the variable names in the rationale.


### Excluding Locally-Initiated Client-Side Cancellations

Locally-initiated client-side cancellations (hedging cancellations, application `CANCELLED`, and `DEADLINE_EXCEEDED`) are excluded from outlier detection counting (`successCount` and `failureCount`). For locally-initiated cancellations (hedging cancellations of non-winning sibling attempts and application-initiated cancellations), this aligns with Envoy's `resetStream()` behavior and prevents false-positive ejections during hedging. For `DEADLINE_EXCEEDED`, this differs from Envoy (which counts deadline expirations as failures for outlier detection); however, because deadline expiration semantics vary between Envoy and gRPC, and because a deadline expiration cannot be definitively attributed to a server failure rather than a network delay, gRPC treats it as a client-side cancellation.

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.

"semantics vary" is pretty vague. "gRPC can't reliably distinguish between cancellation and deadline exceeded cross-language" seems relevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants