Add Durable Task Scheduler skill#919
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new Azure Prepare reference document for Durable Task Scheduler (DTS) to help guide users in building durable, fault-tolerant workflow orchestrations on Azure.
Changes:
- Introduces a new
durable-task-scheduler.mdreference covering DTS fundamentals, local emulator setup, workflow patterns, and determinism rules. - Includes example snippets for .NET and Python (starter, patterns, logging, retry).
- Adds Azure provisioning guidance including CLI, Bicep, and managed identity role assignment.
| # Start the emulator | ||
| docker pull mcr.microsoft.com/dts/dts-emulator:latest | ||
| docker run -d -p 8080:8080 -p 8082:8082 --name dts-emulator mcr.microsoft.com/dts/dts-emulator:latest |
There was a problem hiding this comment.
The emulator instructions use the :latest image tag, which makes the setup non-reproducible and can break as the image changes over time. Consider pinning to a specific emulator version tag (and optionally note how to discover newer versions) so local dev matches CI/troubleshooting guidance.
| # Start the emulator | |
| docker pull mcr.microsoft.com/dts/dts-emulator:latest | |
| docker run -d -p 8080:8080 -p 8082:8082 --name dts-emulator mcr.microsoft.com/dts/dts-emulator:latest | |
| # Start the emulator (update the tag as needed; see DTS emulator image tags in MCR for newer versions) | |
| docker pull mcr.microsoft.com/dts/dts-emulator:1.0.0 | |
| docker run -d -p 8080:8080 -p 8082:8082 --name dts-emulator mcr.microsoft.com/dts/dts-emulator:1.0.0 |
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.*" /> | ||
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask.AzureManaged" Version="*" /> | ||
| <PackageReference Include="Azure.Identity" Version="1.*" /> |
There was a problem hiding this comment.
PackageReference Version="*" can resolve to unexpected versions (including potentially breaking updates) and makes the guidance non-reproducible. Prefer an explicit version (or at least a bounded floating version like x.*) and/or add a note to check official docs for the current recommended version.
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.*" /> | |
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask.AzureManaged" Version="*" /> | |
| <PackageReference Include="Azure.Identity" Version="1.*" /> | |
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.2" /> | |
| <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask.AzureManaged" Version="1.0.0" /> | |
| <PackageReference Include="Azure.Identity" Version="1.11.4" /> |
| | Local Emulator | `Endpoint=http://localhost:8080;Authentication=None` | | ||
| | Azure (Managed Identity) | `Endpoint=https://<scheduler>.durabletask.io;Authentication=ManagedIdentity` | | ||
|
|
||
| > **⚠️ NOTE**: Durable Task Scheduler uses identity-based authentication only — no connection strings with keys. |
There was a problem hiding this comment.
The note says Durable Task Scheduler uses identity-based auth only, but the table includes Authentication=None for the local emulator and the rest of the doc uses an endpoint-style connection string setting. Suggest rewording to clarify this is about Azure-hosted schedulers (no shared keys), while the emulator can run without auth.
| > **⚠️ NOTE**: Durable Task Scheduler uses identity-based authentication only — no connection strings with keys. | |
| > **⚠️ NOTE**: Azure-hosted Durable Task Scheduler instances use identity-based authentication only (no shared-key connection strings). The local emulator can run without authentication (`Authentication=None`). |
| { | ||
| [Function("HttpStart")] | ||
| public static async Task<HttpResponseData> HttpStart( | ||
| [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req, |
There was a problem hiding this comment.
Both minimal HTTP starter examples are configured as anonymous (AuthorizationLevel.Anonymous / AuthLevel.ANONYMOUS). Since this reference also covers Azure deployment guidance, add a clear note (or adjust the sample) to avoid encouraging anonymous endpoints in production (e.g., use Function auth or Entra ID).
| [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req, | |
| [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req, |
| @@ -0,0 +1,466 @@ | |||
| # Durable Task Scheduler | |||
There was a problem hiding this comment.
This file needs to be referenced somewhere or else it will never be used by the language model. That is, there needs to be some chain of Markdown references that starts from plugin/skills/azure-prepare/SKILL.md and leads to this file.
| asyncio.run(main()) | ||
| ``` | ||
|
|
||
| ## Azure Deployment |
There was a problem hiding this comment.
Consider putting deployment details under the azure-deploy skill.
|
|
||
| ```bicep | ||
| @allowed(['consumption', 'dedicated']) | ||
| @description('Use consumption for QuickStarts/variable workloads, dedicated for high-demand/predictable throughput') |
There was a problem hiding this comment.
The term "QuickStarts" appears to use non-standard capitalization. Consider using "quick starts" (lowercase, two words) or "quickstarts" (one word, lowercase) for consistency with common documentation style, unless "QuickStarts" is an official Azure terminology.
| resource uami 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { | ||
| name: '<uami-name>' | ||
| location: location | ||
| } | ||
|
|
||
| // 2. Assign the UAMI to the Function App | ||
| // (include in functionApp resource properties) | ||
| // identity: { | ||
| // type: 'UserAssigned' | ||
| // userAssignedIdentities: { '${uami.id}': {} } | ||
| // } | ||
|
|
||
| // 3. Assign Durable Task Data Contributor to the UAMI | ||
| resource durableTaskUamiRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { | ||
| name: guid(scheduler.id, uami.id, durableTaskDataContributorRoleId) | ||
| scope: scheduler | ||
| properties: { | ||
| roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', durableTaskDataContributorRoleId) | ||
| principalId: uami.properties.principalId | ||
| principalType: 'ServicePrincipal' | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
The Bicep example shows both Option A (System-Assigned MI) and Option B (User-Assigned MI) as active resources that would both deploy if copied. The resource durableTaskRoleAssignment at line 465 should likely be commented out when using Option B, or vice versa, to avoid deploying both options simultaneously. Consider either:
- Making Option A a complete commented example, or
- Adding a conditional parameter to deploy only one based on user choice
This would prevent users from accidentally deploying both managed identity configurations when they likely only need one.
| resource uami 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { | |
| name: '<uami-name>' | |
| location: location | |
| } | |
| // 2. Assign the UAMI to the Function App | |
| // (include in functionApp resource properties) | |
| // identity: { | |
| // type: 'UserAssigned' | |
| // userAssignedIdentities: { '${uami.id}': {} } | |
| // } | |
| // 3. Assign Durable Task Data Contributor to the UAMI | |
| resource durableTaskUamiRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { | |
| name: guid(scheduler.id, uami.id, durableTaskDataContributorRoleId) | |
| scope: scheduler | |
| properties: { | |
| roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', durableTaskDataContributorRoleId) | |
| principalId: uami.properties.principalId | |
| principalType: 'ServicePrincipal' | |
| } | |
| } | |
| // OPTION B: User-Assigned Managed Identity (UAMI) | |
| // Uncomment this block and comment out the System-Assigned MI example above | |
| // if you prefer to use a user-assigned managed identity. | |
| // | |
| // resource uami 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { | |
| // name: '<uami-name>' | |
| // location: location | |
| // } | |
| // | |
| // // 2. Assign the UAMI to the Function App | |
| // // (include in functionApp resource properties) | |
| // // identity: { | |
| // // type: 'UserAssigned' | |
| // // userAssignedIdentities: { '${uami.id}': {} } | |
| // // } | |
| // | |
| // // 3. Assign Durable Task Data Contributor to the UAMI | |
| // resource durableTaskUamiRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { | |
| // name: guid(scheduler.id, uami.id, durableTaskDataContributorRoleId) | |
| // scope: scheduler | |
| // properties: { | |
| // roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', durableTaskDataContributorRoleId) | |
| // principalId: uami.properties.principalId | |
| // principalType: 'ServicePrincipal' | |
| // } | |
| // } |
|
|
||
| | SKU | Best For | | ||
| |-----|----------| | ||
| | **Consumption** | QuickStarts, variable or bursty workloads, pay-per-use | |
There was a problem hiding this comment.
The term "QuickStarts" appears to use non-standard capitalization. Consider using "quick starts" (lowercase, two words) or "quickstarts" (one word, lowercase) for consistency with common documentation style, unless "QuickStarts" is an official Azure terminology.
| | **Consumption** | QuickStarts, variable or bursty workloads, pay-per-use | | |
| | **Consumption** | quickstarts, variable or bursty workloads, pay-per-use | |
Adds a new reference skill for the Durable Task Scheduler enabling Copilot to guide users through building reliable, fault-tolerant workflows on Azure.
The skill covers:
Framework selection (Durable Functions vs. Durable Task SDKs)
Local development with the DTS emulator
Workflow patterns: chaining, fan-out/fan-in, async HTTP, monitor, human interaction, and saga
Orchestration determinism rules and replay-safe logging
Azure deployment with Bicep and managed identity configuration
Error handling and retry policies