Skip to content

Add opt-in Timeout to PurgeInstancesFilter for partial purge#680

Open
YunchuWang wants to merge 5 commits intomainfrom
wangbill/partial-purge-timeout
Open

Add opt-in Timeout to PurgeInstancesFilter for partial purge#680
YunchuWang wants to merge 5 commits intomainfrom
wangbill/partial-purge-timeout

Conversation

@YunchuWang
Copy link
Member

Summary

Add opt-in TimeSpan? Timeout property to PurgeInstancesFilter and send it as google.protobuf.Duration in the gRPC proto request.

Changes

  • PurgeInstancesFilter: Add TimeSpan? Timeout { get; init; } property (default null)
  • GrpcDurableTaskClient.PurgeAllInstancesAsync: Send timeout as google.protobuf.Duration in proto when set
  • Proto: Add google.protobuf.Duration timeout = 4 to PurgeInstanceFilter message

Usage

// Opt-in — existing callers unaffected
var filter = new PurgeInstancesFilter(from, to) { Timeout = TimeSpan.FromSeconds(25) };
var result = await client.PurgeAllInstancesAsync(filter);
// result.IsComplete == false → call again

Breaking Changes

None. Timeout defaults to null — existing behavior unchanged.

Replaces #679 (closed).

Dependencies

- Add TimeSpan? Timeout property to PurgeInstancesFilter (opt-in, default null)
- Send timeout as google.protobuf.Duration in gRPC request when set
- Add timeout field (4) to PurgeInstanceFilter proto message
- Zero breaking changes: existing callers unaffected
Copilot AI review requested due to automatic review settings March 19, 2026 05:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an opt-in, per-call timeout for purge operations by extending the client-side PurgeInstancesFilter API and propagating the value through the gRPC contract to enable time-bounded (“partial”) purge behavior when supported by the backend.

Changes:

  • Add TimeSpan? Timeout (init-only) to PurgeInstancesFilter.
  • Send Timeout as google.protobuf.Duration in GrpcDurableTaskClient.PurgeAllInstancesAsync when provided.
  • Extend the gRPC proto PurgeInstanceFilter message with a new timeout field.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/Client/Core/PurgeInstancesFilter.cs Adds the new optional Timeout property and XML documentation.
src/Client/Grpc/GrpcDurableTaskClient.cs Maps PurgeInstancesFilter.Timeout into the gRPC request message.
src/Grpc/orchestrator_service.proto Extends PurgeInstanceFilter with google.protobuf.Duration timeout = 4.

You can also share your feedback on Copilot code review. Take the survey.

- Add ArgumentOutOfRangeException for zero/negative Timeout in PurgeAllInstancesAsync
- Update PurgeInstancesFilter.Timeout XML docs to note backend-dependent semantics
- Add 3 unit tests for Timeout validation (negative, zero, positive)
Copilot AI review requested due to automatic review settings March 20, 2026 22:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an optional timeout to purge operations so callers can request time-bounded (“partial”) purges and loop until completion, improving reliability for large purge workloads over gRPC.

Changes:

  • Added TimeSpan? Timeout to PurgeInstancesFilter (opt-in, default null).
  • Forwarded Timeout through GrpcDurableTaskClient.PurgeAllInstancesAsync as google.protobuf.Duration, with validation for non-positive values.
  • Extended the gRPC proto PurgeInstanceFilter message to include a timeout field, plus added unit tests around timeout validation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
test/Client/Grpc.Tests/GrpcDurableTaskClientTests.cs Adds unit tests for Timeout validation behavior
src/Grpc/orchestrator_service.proto Adds google.protobuf.Duration timeout = 4 to purge filter message
src/Client/Grpc/GrpcDurableTaskClient.cs Validates and maps PurgeInstancesFilter.Timeout into the protobuf request
src/Client/Core/PurgeInstancesFilter.cs Adds the new Timeout property with XML documentation

{
// Arrange
var client = this.CreateClient();
var filter = new PurgeInstancesFilter { Timeout = TimeSpan.FromSeconds(30) };
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

PurgeInstancesFilter is a positional record without an explicit parameterless constructor; object creation without () (i.e., new PurgeInstancesFilter { ... }) won’t compile. Use new PurgeInstancesFilter() (or provide the positional args) before the object initializer.

Copilot uses AI. Check for mistakes.
if (filter.Timeout.Value <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(
nameof(filter),
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

The ArgumentOutOfRangeException uses paramName: nameof(filter), which points at the whole filter rather than the Timeout property that’s invalid. Consider using nameof(PurgeInstancesFilter.Timeout) / nameof(filter.Timeout) so callers get a more precise exception parameter name.

Suggested change
nameof(filter),
nameof(PurgeInstancesFilter.Timeout),

Copilot uses AI. Check for mistakes.
"Timeout must be a positive TimeSpan.");
}

request.PurgeInstanceFilter.Timeout = Google.Protobuf.WellKnownTypes.Duration.FromTimeSpan(filter.Timeout.Value);
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

Duration.FromTimeSpan(...) will throw ArgumentOutOfRangeException for very large values (e.g., TimeSpan.MaxValue). Since this is a public opt-in API, consider validating/catching that case and throwing a clearer ArgumentOutOfRangeException that consistently references the Timeout parameter.

Suggested change
request.PurgeInstanceFilter.Timeout = Google.Protobuf.WellKnownTypes.Duration.FromTimeSpan(filter.Timeout.Value);
try
{
request.PurgeInstanceFilter.Timeout = Google.Protobuf.WellKnownTypes.Duration.FromTimeSpan(filter.Timeout.Value);
}
catch (ArgumentOutOfRangeException ex)
{
throw new ArgumentOutOfRangeException(
nameof(filter.Timeout),
filter.Timeout.Value,
"Timeout is outside the supported range for gRPC duration values.",
ex);
}

Copilot uses AI. Check for mistakes.
{
// Arrange
var client = this.CreateClient();
var filter = new PurgeInstancesFilter { Timeout = TimeSpan.FromSeconds(-1) };
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

PurgeInstancesFilter is a positional record without an explicit parameterless constructor; object creation without () (i.e., new PurgeInstancesFilter { ... }) won’t compile. Use new PurgeInstancesFilter() (or provide the positional args) before the object initializer.

Copilot uses AI. Check for mistakes.
{
// Arrange
var client = this.CreateClient();
var filter = new PurgeInstancesFilter { Timeout = TimeSpan.Zero };
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

PurgeInstancesFilter is a positional record without an explicit parameterless constructor; object creation without () (i.e., new PurgeInstancesFilter { ... }) won’t compile. Use new PurgeInstancesFilter() (or provide the positional args) before the object initializer.

Copilot uses AI. Check for mistakes.
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.

3 participants