title | description | author | ms.topic | ms.date | ms.author | ms.devlang | ms.custom |
---|---|---|---|---|---|---|---|
Overview of Durable Functions in the .NET isolated worker - Azure |
Learn about Durable Functions in the Azure Functions .NET isolated worker process, which supports non-LTS versions of .NET and .NET Framework apps. |
jviau |
overview |
01/24/2023 |
azfuncdf |
csharp |
devx-track-dotnet |
This article is an overview of Durable Functions in the .NET isolated worker. The isolated worker allows your Durable Functions app to run on a .NET version different than that of the Azure Functions host.
Using this model lets you get all the great benefits that come with the Azure Functions .NET isolated worker process. For more information, see Benefits of the isolated worker model. Additionally, this new SDK includes some new features.
- Orchestration input can be injected directly:
MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context, T input)
- Support for strongly typed calls and class-based activities and orchestrations (NOTE: in preview. For more information, see here.)
- Plus all the benefits of the Azure Functions .NET isolated worker.
Requirement: add <PackageReference Include="Microsoft.DurableTask.Generators" Version="1.0.0-preview.1" />
to your project.
By adding the source generator package, you get access to two new features:
- Class-based activities and orchestrations, an alternative way to write Durable Functions. Instead of "function-based", you write strongly typed classes, which inherit types from the Durable SDK.
- Strongly typed extension methods for invoking sub orchestrations and activities. These extension methods can also be used from "function-based" activities and orchestrations.
public static class MyFunctions
{
[Function(nameof(MyActivity))]
public static async Task<string> MyActivity([ActivityTrigger] string input)
{
// implementation
}
[Function(nameof(MyOrchestration))]
public static async Task<string> MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context, string input)
{
// implementation
return await context.CallActivityAsync(nameof(MyActivity), input);
}
}
[DurableTask(nameof(MyActivity))]
public class MyActivity : TaskActivity<string, string>
{
private readonly ILogger logger;
public MyActivity(ILogger<MyActivity> logger) // activites have access to DI.
{
this.logger = logger;
}
public async override Task<string> RunAsync(TaskActivityContext context, string input)
{
// implementation
}
}
[DurableTask(nameof(MyOrchestration))]
public class MyOrchestration : TaskOrchestrator<string, string>
{
public async override Task<string> RunAsync(TaskOrchestrationContext context, string input)
{
ILogger logger = context.CreateReplaySafeLogger<MyOrchestration>(); // orchestrations do NOT have access to DI.
// An extension method was generated for directly invoking "MyActivity".
return await context.CallMyActivityAsync(input);
}
}
Durable entities are supported in the .NET isolated worker. See developer's guide.
This guide assumes you're starting with a .NET Durable Functions 2.x project.
The first step is to update your project to Azure Functions .NET isolated. Then, update your Durable Functions NuGet package references.
Old:
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.9.0" />
</ItemGroup>
New:
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.0" />
</ItemGroup>
Durable Functions for .NET isolated worker is an entirely new package with different types and namespaces. There are required changes to your code as a result, but many of the APIs line up with no changes needed.
The schema for Durable Functions .NET isolated worker and Durable Functions 2.x has remained the same, no changes should be needed.
This table isn't an exhaustive list of changes.
2.x | Isolated |
---|---|
IDurableOrchestrationClient |
DurableTaskClient |
IDurableOrchestrationClient.StartNewAsync |
DurableTaskClient.ScheduleNewOrchestrationInstanceAsync |
IDurableEntityClient.SignalEntityAsync |
DurableTaskClient.Entities.SignalEntityAsync |
IDurableEntityClient.ReadEntityStateAsync |
DurableTaskClient.Entities.GetEntityAsync |
IDurableEntityClient.ListEntitiesAsync |
DurableTaskClient.Entities.GetAllEntitiesAsync |
IDurableEntityClient.CleanEntityStorageAsync |
DurableTaskClient.Entities.CleanEntityStorageAsync |
IDurableOrchestrationContext |
TaskOrchestrationContext |
IDurableOrchestrationContext.GetInput<T>() |
TaskOrchestrationContext.GetInput<T>() or inject input as a parameter: MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context, T input) |
DurableActivityContext |
No equivalent |
DurableActivityContext.GetInput<T>() |
Inject input as a parameter MyActivity([ActivityTrigger] T input) |
IDurableOrchestrationContext.CallActivityWithRetryAsync |
TaskOrchestrationContext.CallActivityAsync , include TaskOptions parameter with retry details. |
IDurableOrchestrationContext.CallSubOrchestratorWithRetryAsync |
TaskOrchestrationContext.CallSubOrchestratorAsync , include TaskOptions parameter with retry details. |
IDurableOrchestrationContext.CallHttpAsync |
TaskOrchestrationContext.CallHttpAsync |
IDurableOrchestrationContext.CreateReplaySafeLogger(ILogger) |
TaskOrchestrationContext.CreateReplaySafeLogger<T>() or TaskOrchestrationContext.CreateReplaySafeLogger(string) |
IDurableOrchestrationContext.CallEntityAsync |
TaskOrchestrationContext.Entities.CallEntityAsync |
IDurableOrchestrationContext.SignalEntity |
TaskOrchestrationContext.Entities.SignalEntityAsync |
IDurableOrchestrationContext.LockAsync |
TaskOrchestrationContext.Entities.LockEntitiesAsync |
IDurableOrchestrationContext.IsLocked |
TaskOrchestrationContext.Entities.InCriticalSection |
IDurableEntityContext |
TaskEntityContext . |
IDurableEntityContext.EntityName |
TaskEntityContext.Id.Name |
IDurableEntityContext.EntityKey |
TaskEntityContext.Id.Key |
IDurableEntityContext.OperationName |
TaskEntityOperation.Name |
IDurableEntityContext.FunctionBindingContext |
Removed, add FunctionContext as an input parameter |
IDurableEntityContext.HasState |
TaskEntityOperation.State.HasState |
IDurableEntityContext.BatchSize |
Removed |
IDurableEntityContext.BatchPosition |
Removed |
IDurableEntityContext.GetState |
TaskEntityOperation.State.GetState |
IDurableEntityContext.SetState |
TaskEntityOperation.State.SetState |
IDurableEntityContext.DeleteState |
TaskEntityOperation.State.SetState(null) |
IDurableEntityContext.GetInput |
TaskEntityOperation.GetInput |
IDurableEntityContext.Return |
Removed. Method return value used instead. |
IDurableEntityContext.SignalEntity |
TaskEntityContext.SignalEntity |
IDurableEntityContext.StartNewOrchestration |
TaskEntityContext.ScheduleNewOrchestration |
IDurableEntityContext.DispatchAsync |
TaskEntityDispatcher.DispatchAsync . Constructor params removed. |
IDurableOrchestrationClient.GetStatusAsync |
DurableTaskClient.GetInstanceAsync |
- Serialization default behavior has changed from
Newtonsoft.Json
toSystem.Text.Json
. For more information, see here.