Add multi-version support to [DurableTask] annotations#751
Open
halspang wants to merge 1 commit into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds multi-version support to [DurableTask] version annotations across reflection-based registration and the source generator, and updates worker work-item filter generation to respect CurrentOrOlder versioning semantics.
Changes:
- Parse comma-separated
DurableTaskAttribute.Versionvalues into a distinct ordered version set and register tasks under each declared version. - Update the source generator to emit multi-version call helpers that require a
versionparameter with runtime validation. - Narrow auto-generated worker work-item filters to versions
<= workerVersionwhenVersionMatchStrategy.CurrentOrOlderis enabled, with expanded test coverage.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| CHANGELOG.md | Documents the new multi-version attribute support and filter narrowing behavior. |
| src/Abstractions/DurableTaskAttribute.cs | Updates XML docs to describe comma-separated multi-version semantics and validation rules. |
| src/Abstractions/TypeExtensions.cs | Adds reflection-side parsing for multi-version attributes (GetDurableTaskVersions) and preserves GetDurableTaskVersion semantics. |
| src/Abstractions/DurableTaskRegistry.Orchestrators.cs | Fans out orchestrator type/singleton registrations to all declared versions. |
| src/Abstractions/DurableTaskRegistry.Activities.cs | Fans out activity type/singleton registrations to all declared versions. |
| src/Abstractions/DurableTaskRegistry.cs | Adds shared “register across all versions” helper for activities. |
| src/Generators/DurableTaskSourceGenerator.cs | Implements multi-version parsing, deduplication, collision detection, and version-parameter helper generation with runtime guards. |
| src/Worker/Core/DurableTaskWorkerWorkItemFilters.cs | Narrows generated versions for CurrentOrOlder by comparing against worker version. |
| test/Abstractions.Tests/DurableTaskAttributeVersionTests.cs | Adds tests for multi-version parsing, trimming/dedup, unversioned behavior, and whitespace-only entry rejection. |
| test/Abstractions.Tests/DurableTaskRegistryVersioningTests.cs | Adds tests ensuring multi-version types register under each version and collisions are rejected. |
| test/Generators.Tests/VersionedOrchestratorTests.cs | Adds generator snapshot test for multi-version orchestrators producing version-parameter helpers and guards. |
| test/Generators.Tests/VersionedActivityTests.cs | Adds generator snapshot test for multi-version activities producing version-parameter helpers and guards. |
| test/Worker/Core.Tests/DependencyInjection/UseWorkItemFiltersTests.cs | Adds CurrentOrOlder filter tests that validate dropping newer versions and retaining unversioned + older versions. |
| test/Worker/Core.Tests/DurableTaskFactoryVersioningTests.cs | Adds factory resolution test covering coexistence of unversioned and multi-version activity registrations. |
Comments suppressed due to low confidence (1)
src/Worker/Core/DurableTaskWorkerWorkItemFilters.cs:118
- Under MatchStrategy.CurrentOrOlder, workerVersion filtering can remove all versioned registrations for a name, leaving only the unversioned "" entry. The current
normalized.Length == 1 && normalized[0].Length == 0check then returns an empty Versions list (wildcard), which widens the backend filter and can cause newer versioned work items to be streamed (and then rejected) even though the registry originally had versioned registrations (which disable unversioned fallback). Consider emitting the wildcard only when the original registrations for the name were truly unversioned-only (no non-empty versions) before filtering; otherwise return[""]to restrict to unversioned only.
// Unversioned-only: emit the wildcard match-all (empty list) so the backend can deliver
// versioned work items that the factory will resolve via unversioned fallback. Without
// this, callers asking for a specific version would be filtered out at the backend even
// though the worker can handle them.
if (normalized.Length == 1 && normalized[0].Length == 0)
{
return [];
}
| # Changelog | ||
|
|
||
| ## Unreleased | ||
| - Support declaring multiple versions in a single `[DurableTask]` attribute via a comma-separated list (for example `[DurableTask("MyActivity", Version = "1.0.0,1.1.0")]`); each version is registered and plumbed through code generation. Narrow auto-generated work item filters to current-or-older versions under the `CurrentOrOlder` match strategy. |
d324252 to
5c4eda7
Compare
The Version property now accepts a comma-separated list (e.g. "v1,v2"), registering the type under each declared version and emitting call helpers that take a required 'version' parameter validated against the declared set. Single-version and unversioned behavior is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
5c4eda7 to
dd42561
Compare
Comment on lines
+101
to
110
| static IReadOnlyList<string> GetFilterVersions(IEnumerable<string?> versions, string? workerVersion) | ||
| { | ||
| // Normalize null to "" so an unversioned registration appears consistently. | ||
| string[] normalized = versions | ||
| .Select(version => version ?? string.Empty) | ||
| .Distinct(StringComparer.OrdinalIgnoreCase) | ||
| .OrderBy(version => version, StringComparer.OrdinalIgnoreCase) | ||
| .Where(version => workerVersion == null || TaskOrchestrationVersioningUtils.CompareVersions(workerVersion, version) >= 0) | ||
| .ToArray(); | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
What changed?
The Version property now accepts a comma-separated list (e.g. "v1,v2"), registering the type under each declared version and emitting call helpers that take a required 'version' parameter validated against the declared set. Single-version and unversioned behavior is unchanged.
Why is this change needed?
This allows customers to specify multiple versions of a single orchestration/activity without having to duplicate the code in their own codebase.
Issues / work items
Project checklist
release_notes.mdAI-assisted code disclosure (required)
Was an AI tool used? (select one)
If AI was used:
AI verification (required if AI was used):
Testing
Automated tests
Manual validation (only if runtime/behavior changed)
Notes for reviewers