Skip to content

Add opt-in version-check exclusions for unversioned orchestrations - #1408

Open
wangbill (YunchuWang) wants to merge 9 commits into
mainfrom
yunchuwang-df-purge-core-versioning
Open

wangbill (YunchuWang) wants to merge 9 commits into
mainfrom
yunchuwang-df-purge-core-versioning

Conversation

@YunchuWang

@YunchuWang wangbill (YunchuWang) commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

Summary

Keep worker-version exemptions for automatically registered, unversioned infrastructure orchestrations internal to Core and its Functions host integration.

The orchestration dispatcher applies worker version policies before middleware and orchestration execution. A versioned worker therefore cannot use middleware to execute an unversioned infrastructure orchestration without rejecting or failing it, or disabling version checks for business orchestrations.

VersioningSettings.ExcludedOrchestrationNames is an internal, instance-scoped, initially empty ISet<string> using exact, case-sensitive ordinal name matching. It is not a public customer-configurable allow list. An exclusion applies only when the execution version is null or empty. Nonempty versions, including whitespace, remain subject to the existing matching and failure policies even when their name is in the set.

Scope and compatibility

  • Existing constructor signatures and default versioning behavior are unchanged.
  • Only the worker version gate is skipped. Name/version registration and lookup, middleware, history, and execution versions are unchanged.
  • Replay and ContinueAsNew use the same gate; continuing with a nonempty version reapplies the normal policy.
  • The Functions integration automatically populates the internal set before starting the worker; customers do not maintain an exclusion list. The set must not be mutated while the worker runs.
  • No provider-specific names, dependencies, backend operations, package version changes, or protocol changes are introduced.

Infrastructure identities remain owned and validated by their integrations, not hardcoded in Core. Core grants the exact WebJobs Functions host friend access using its full signing public key; normal consumers cannot access the internal collection. Older workers continue applying their existing version policies; deployments must account for that before routing unversioned infrastructure executions to them. Friend access exposes Core's internal surface to the host and adds internal-ABI/signing compatibility requirements; it is not an authentication or security boundary.

The net change in this PR is limited to the internal generic Core version exemption, the signed Functions-host friendship, tests, and documentation. The optional large payload purge interface package is owned by the SDK repository in microsoft/durabletask-dotnet#805, not by this repository. Core contains no purge contract models or type forwarders and has no dependency on that package or SDK Client. The solution, dependency manifest, and CI/release wiring have no net changes here.

Validation

Focused tests exercise the real dispatcher, middleware, and executor, with an in-memory backend test double recording completion and abandonment.

dotnet test .\test\DurableTask.Core.Tests\DurableTask.Core.Tests.csproj --no-restore --filter 'FullyQualifiedName~VersionSettingsTests|FullyQualifiedName~TaskOrchestrationDispatcherVersioningTests' --verbosity minimal
dotnet build .\src\DurableTask.Core\DurableTask.Core.csproj --no-restore --configuration Release --verbosity minimal
  • 40 tests passed on each of net8.0 and net48, including the new public-surface regression.
  • Core Release build succeeded with zero warnings and errors, without an SDK version property.
  • Coverage includes empty defaults, exact name/case/prefix boundaries, null/empty versions, nonempty same-name versions, unchanged Strict/CurrentOrOlder/None and Reject/Fail behavior, normal object resolution, replay across three generations, and ContinueAsNew to a nonempty version.
  • Before the dispatcher guard was added, six exemption behavior tests failed as expected; they passed after the guard was added.
  • A separate Core-only consumer restored the actual local nupkg and verified that its dependency graph excludes SDK Client and the purge interface package, and that Core defines or forwards none of the purge contract types.

No cloud, storage, SQL, or mixed-worker deployment suites were run for this Core change.

October 6 internal registration follow-up

Core commits 1ac92281 and 31b40089 remove the public exclusion surface and add the exact Microsoft.Azure.WebJobs.Extensions.DurableTask friend declaration. Signed Release uses the host's full .NET Foundation public key (host token 014045d636e89289, distinct from Core's unchanged d53979610a6e89dd); unsigned Core builds retain the existing test friends and declare the host by simple name. The dispatcher guard is unchanged. No SDK orchestration name or dependency was added to Core.

The companion Functions source in Azure/azure-functions-durable-extension#3556, commit bba3cf82, retains automatic registration of the exact marked .NET isolated infrastructure orchestration. Actual host Debug and Release builds are both signed and compiled against the freshly packed Core 3.10.1-local.ivt.20261006.31b40089. The host's full key matches the packaged Core friend metadata. Public reflection does not expose the collection; an ordinary consumer can compile the unchanged public versioning API but cannot compile collection access (actual Roslyn diagnostic CS1061).

Fresh local scoped results: 40 Core cases on each of net8.0/net48, plus 73 host and 78 worker cases on each of net8.0/net10.0. Package hashes, all resolved Core DLL copies, and the validated source bytes were checked. These are local verification artifacts, not production package releases or a claim that hosted CI is green. Actual compatible Core publication and downstream dependency updates remain merge/release prerequisites.

Allow hosts to exempt exact registered infrastructure orchestration names from worker version checks only for null or empty execution versions. Preserve existing policies, execution identities, and constructor signatures.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Move both test files into the active lowercase test project so they are compiled and executed.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 Medium severity

Open (2)
What changed in this PR

Adds opt-in exclusions for unversioned infrastructure orchestrations while preserving existing version policies.

Changes:

  • Adds ordinal, instance-scoped orchestration exclusions.
  • Bypasses checks only for excluded null/empty-version executions.
  • Adds documentation and dispatcher/settings tests.
File Summary
Test/​DurableTask.Core.Tests/​VersionSettingsTests.cs Adds settings tests. Moderate (3 votes): outside the active test project, so tests are not compiled or run.
Test/​DurableTask.Core.Tests/​TaskOrchestrationDispatcherVersioningTests.cs Adds dispatcher tests. Moderate (3 votes): outside the active test project, so tests are not compiled or run.
src/​DurableTask.Core/​TaskOrchestrationDispatcher.cs Applies exclusions at the version gate.
src/​DurableTask.Core/​Settings/​VersioningSettings.cs Adds exclusion configuration.
docs/​features/​versioning.md Documents configuration and behavior.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/DurableTask.Core.Tests/VersionSettingsTests.cs
Move the shared purge models into Core with their existing null-only token checks and disposition values. Add an optional BCL-only service client interface without changing existing client contracts or the version exemption.

Copilot-Session: 883b4cbd-e93c-4d4e-8cb8-ffcf69525cfa
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Document that DateTime.MaxValue leaves the deadline unspecified by the caller and that the backing service may apply a default. Setting auto-purge records the choice without managing a runner.

Copilot-Session: 883b4cbd-e93c-4d4e-8cb8-ffcf69525cfa
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 24, 2026 16:07
@YunchuWang wangbill (YunchuWang) changed the title Add opt-in version-check exclusions for unversioned orchestrations Add large payload purge capability and unversioned orchestration support Sep 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The added tests are outside the active lowercase test project and are not compiled or executed.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 3 Medium severity

Open (3)

Comment thread Test/DurableTask.Core.Tests/LargePayloadPurgeTests.cs Outdated
Keep Core free of purge contracts and SDK Client dependencies. Add the standalone interface package, SDK model identity and Core boundary tests, and standard build/sign/pack wiring. Require an explicitly supplied compatible SDK package until the model release is available.

Copilot-Session: 883b4cbd-e93c-4d4e-8cb8-ffcf69525cfa
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The dedicated purge contract stage already builds its product project. Leave existing Core, Azure Storage, and Emulator validation independent of the SDK release prerequisite.

Copilot-Session: 883b4cbd-e93c-4d4e-8cb8-ffcf69525cfa
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 24, 2026 21:03
@YunchuWang wangbill (YunchuWang) changed the title Add large payload purge capability and unversioned orchestration support Add standalone purge service abstractions and unversioned orchestration support Sep 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Core test coverage is not wired into the active project, and the boundary test references the wrong tombstone type.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 3 Medium severity

Open (3)
Resolved since last review (1)

Comment thread Test/DurableTask.Core.Tests/CorePackageBoundaryTests.cs Outdated
Remove the standalone contract project, extraction-only tests, and SDK dependency/release wiring from this repository. Restore all non-versioning files to the original feature baseline while preserving the generic opt-in version exemption unchanged.

Copilot-Session: 883b4cbd-e93c-4d4e-8cb8-ffcf69525cfa
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 24, 2026 21:47
@YunchuWang wangbill (YunchuWang) changed the title Add standalone purge service abstractions and unversioned orchestration support Add opt-in version-check exclusions for unversioned orchestrations Sep 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Move the new tests into the active lowercase test project and rerun the suite.

Review effort: Lite
Findings: 2 Medium severity

Open (2)
Resolved since last review (1)

@YunchuWang
wangbill (YunchuWang) marked this pull request as ready for review September 29, 2026 17:07
Move the two versioning test files into the existing lowercase test project directory so case-sensitive checkouts include them. Preserve both file blobs unchanged.

Copilot-Session: 883b4cbd-e93c-4d4e-8cb8-ffcf69525cfa
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 1, 2026 16:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

No unresolved blocking issues were identified.

Review effort: Lite
Findings: None

Resolved since last review (2)

@YunchuWang

Copy link
Copy Markdown
Member Author

Blob auto-purge: staged merge and release order

This PR is stage 1 of the cross-repository integration. Review can proceed in parallel, but merge/release must follow the dependency order:

  1. Core #1408: merge and publish a compatible Core release containing the required version-exemption API.
  2. SDK #805: use the published Core prerequisite, merge, and publish the compatible Client/Abstractions/Grpc/Worker dependency closure, then the contracts package, then the Blob implementation package.
  3. Functions #3556: commit actual compatible published Core/SDK/contracts references and pass clean-cache restore/build/tests and required CI before merging; then publish the host, base worker and optional purge worker packages.
  4. AzureManaged provider companion (internal): update its committed dependencies to those actual releases, satisfy remaining review/policy requirements, validate without local substitutions, then merge and publish last.

Gate: completing four consecutive merges is not sufficient. Each upstream package must actually be published and its complete dependency closure restorable before the next consumer is merged. Local validation artifacts or matching version numbers alone are not release-readiness evidence. Keep auto-purge explicitly disabled until the compatible worker/provider/backend/storage rollout is verified.

@halspang

halspang commented Oct 6, 2026

Copy link
Copy Markdown
Member

I don't know if this is something that we should do. The more ways we add to ignore a system built to accept/deny work the more likely it is to be mis-used.

I also think, from a CX side, it's odd that we can allow users to enable features that require infrastructure orchestrations but then also require they add them manually to this filter.

What I would do instead is just keep a constant list of all the infrastructure orchestrations that exist since we own them. We then compare against that constant list instead of having users manually add to the exclusion list. You could also just have the feature registration add to the list, but I'd rather not have that be specifiable since it's a very specific case we're accounting for.

You could also keep this, but make it internal and then have the extension methods enabling the feature add it to this. Though I'd prefer if we didn't keep it around in general.

wangbill (YunchuWang) and others added 2 commits October 6, 2026 10:47
Make VersioningSettings.ExcludedOrchestrationNames internal instead of public; it was never shipped (only in this open PR) and is reserved for the Durable Task Framework's own approved integrations, not a customer-configurable allow list. Grant friend access to the exact Azure Functions Durable Task in-process host assembly via InternalsVisibleTo, using its full public key when Core is signed (Release) and simple name when Core is unsigned (Debug/test), matching the existing test-friend convention. No business version policy, dispatcher behavior, or other public API changes.

Copilot-Session: 883b4cbd-e93c-4d4e-8cb8-ffcf69525cfa
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove the inaccurate '(in-process worker)' wording from the InternalsVisibleTo comment; the WebJobs extension is a separate host, not the language worker.

Copilot-Session: 883b4cbd-e93c-4d4e-8cb8-ffcf69525cfa
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 6, 2026 15:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Critical test issues remain with signed Release access and reflection-based internal getter access.

Review effort: Lite
Findings: 2 High severity

Open (2)

};
if (configureExclusion)
{
settings.ExcludedOrchestrationNames.Add(InternalName);
PropertyInfo internalProperty = typeof(VersioningSettings).GetProperty(
"ExcludedOrchestrationNames", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.IsNotNull(internalProperty, "ExcludedOrchestrationNames must remain accessible internally.");
Assert.IsTrue(internalProperty.GetMethod.IsAssembly, "The getter must be internal, not public or private.");
@YunchuWang

Copy link
Copy Markdown
Member Author

halspang Addressed the public API/CX concern in this PR and the companion Functions PR #3556.

  • ExcludedOrchestrationNames is now internal, not a customer-configurable exclusion list. Functions retains its existing automatic registration of the exact marked .NET isolated infrastructure orchestration; customers only enable the feature.
  • Core stays generic: no SDK orchestration name is hardcoded and no reverse SDK dependency was added. The actual WebJobs host receives friend access via its full signing public key, not the isolated worker assembly or a token-only declaration.
  • The exemption still requires an exact ordinal name match and a null/empty execution version. Nonempty versions (including whitespace), business version checks, and normal orchestration lookup are unchanged.

Changes: Core 1ac92281 + 31b40089; Functions bba3cf82. Actual signed host Debug/Release builds compiled against the final Core package; ordinary nonfriend access fails, and public reflection does not expose the collection. The focused Core/host/worker cases passed locally against that exact closure.

This uses the internal feature-registration alternative from your comment, rather than a public bypass knob or SDK-specific constants in Core. IVT exposes the host to Core's internal surface and adds signing/internal-ABI release coupling; it is not a security boundary. Compatible Core publication and real downstream dependency updates remain pre-merge gates; no production package or PR merge was performed.

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.

3 participants