Add opt-in Timeout to PurgeInstancesFilter for partial purge#680
Add opt-in Timeout to PurgeInstancesFilter for partial purge#680YunchuWang wants to merge 5 commits intomainfrom
Conversation
- 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
There was a problem hiding this comment.
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) toPurgeInstancesFilter. - Send
Timeoutasgoogle.protobuf.DurationinGrpcDurableTaskClient.PurgeAllInstancesAsyncwhen provided. - Extend the gRPC proto
PurgeInstanceFiltermessage with a newtimeoutfield.
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)
…icrosoft/durabletask-dotnet into wangbill/partial-purge-timeout
There was a problem hiding this comment.
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? TimeouttoPurgeInstancesFilter(opt-in, defaultnull). - Forwarded
TimeoutthroughGrpcDurableTaskClient.PurgeAllInstancesAsyncasgoogle.protobuf.Duration, with validation for non-positive values. - Extended the gRPC proto
PurgeInstanceFiltermessage to include atimeoutfield, 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) }; |
There was a problem hiding this comment.
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.
| if (filter.Timeout.Value <= TimeSpan.Zero) | ||
| { | ||
| throw new ArgumentOutOfRangeException( | ||
| nameof(filter), |
There was a problem hiding this comment.
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.
| nameof(filter), | |
| nameof(PurgeInstancesFilter.Timeout), |
| "Timeout must be a positive TimeSpan."); | ||
| } | ||
|
|
||
| request.PurgeInstanceFilter.Timeout = Google.Protobuf.WellKnownTypes.Duration.FromTimeSpan(filter.Timeout.Value); |
There was a problem hiding this comment.
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.
| 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); | |
| } |
| { | ||
| // Arrange | ||
| var client = this.CreateClient(); | ||
| var filter = new PurgeInstancesFilter { Timeout = TimeSpan.FromSeconds(-1) }; |
There was a problem hiding this comment.
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.
| { | ||
| // Arrange | ||
| var client = this.CreateClient(); | ||
| var filter = new PurgeInstancesFilter { Timeout = TimeSpan.Zero }; |
There was a problem hiding this comment.
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.
Summary
Add opt-in
TimeSpan? Timeoutproperty toPurgeInstancesFilterand send it asgoogle.protobuf.Durationin the gRPC proto request.Changes
PurgeInstancesFilter: AddTimeSpan? Timeout { get; init; }property (default null)GrpcDurableTaskClient.PurgeAllInstancesAsync: Send timeout asgoogle.protobuf.Durationin proto when setgoogle.protobuf.Duration timeout = 4toPurgeInstanceFiltermessageUsage
Breaking Changes
None.
Timeoutdefaults to null — existing behavior unchanged.Replaces #679 (closed).
Dependencies