|
| 1 | +--- |
| 2 | +title: Migrating Azure Functions in-process to Isolated Worker |
| 3 | +summary: Instructions on how to migrate Azure Functions in-process to Azure Functions Isolated Worker |
| 4 | +component: ASBFunctionsWorker |
| 5 | +reviewed: 2024-07-29 |
| 6 | +related: |
| 7 | + - nservicebus/hosting/azure-functions-service-bus/in-process |
| 8 | + - samples/azure-functions/service-bus |
| 9 | + - nservicebus/hosting/azure-functions-service-bus |
| 10 | + - samples/azure-functions/service-bus-worker |
| 11 | +isUpgradeGuide: false |
| 12 | +--- |
| 13 | + |
| 14 | +Microsoft has confirmed that .NET 8.0 will be the last LTS to support the in-process hosting model and .NET 6.0 LTS will reach end of support in November 2024. Migrating to the isolated worker hosting model is strongly advised. |
| 15 | + |
| 16 | +> [!NOTE] |
| 17 | +> When migrating from the in-process model to the isolated worker model, it is highly recommended that you follow [Microsoft's migration guide](https://learn.microsoft.com/en-us/azure/azure-functions/migrate-dotnet-to-isolated-model?tabs=net8) to start with, as this guide specifically covers the NServiceBus functionality. |
| 18 | +
|
| 19 | +## Key differences |
| 20 | + |
| 21 | +Find more detailed information about the [difference between the in-process and isolated worker model](https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-in-process-differences). |
| 22 | + |
| 23 | +- **In-process**: Functions run within the Azure Functions runtime, share the same process an AppDomain. |
| 24 | +- **Isolated worker**: Functions are isolated from the Azure Functions runtime and run in a separate process. |
| 25 | + |
| 26 | +## Update project file |
| 27 | + |
| 28 | +### Framework |
| 29 | + |
| 30 | +It's recommended to update the `TargetFramework` in your `.csproj` file to `net8.0`. |
| 31 | + |
| 32 | +### Package references |
| 33 | + |
| 34 | +- Remove `NServiceBus.AzureFunctions.InProcess.ServiceBus` from your `.csproj` file. |
| 35 | +- Add `NServiceBus.AzureFunctions.Worker.ServiceBus` to your `.csproj` file with the appropriate version based on the version of NServiceBus in your project. |
| 36 | + |
| 37 | +## Update host configuration |
| 38 | + |
| 39 | +A `Program.cs` file is required and replaces any file that has the FunctionsStartup attribute like the `Startup.cs` when migrating to the isolated worker model. |
| 40 | + |
| 41 | +This is an example of and in-process host configuration using `Startup.cs` |
| 42 | + |
| 43 | +```csharp |
| 44 | +[assembly: FunctionsStartup(typeof(Startup))] |
| 45 | +[assembly: NServiceBusTriggerFunction(Startup.EndpointName)] |
| 46 | + |
| 47 | +class Startup : FunctionsStartup |
| 48 | +{ |
| 49 | + public const string EndpointName = "DemoEndpoint"; |
| 50 | + |
| 51 | + public override void Configure(IFunctionsHostBuilder builder) |
| 52 | + { |
| 53 | + builder.UseNServiceBus(); |
| 54 | + } |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +A migrated host configuration for isolated worker to `Program.cs` would look like the following |
| 59 | + |
| 60 | +```csharp |
| 61 | +[assembly: NServiceBusTriggerFunction(Program.EndpointName)] |
| 62 | + |
| 63 | +public class Program |
| 64 | +{ |
| 65 | + public const string EndpointName = "DemoEndpoint"; |
| 66 | + |
| 67 | + public static Task Main() |
| 68 | + { |
| 69 | + var host = new HostBuilder() |
| 70 | + .ConfigureFunctionsWorkerDefaults() |
| 71 | + .UseNServiceBus() |
| 72 | + .Build(); |
| 73 | + |
| 74 | + return host.RunAsync(); |
| 75 | + } |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +## Update trigger functions |
| 80 | + |
| 81 | +Remember first to follow Microsoft's migration guide to update the [trigger functions and bindings](https://learn.microsoft.com/en-us/azure/azure-functions/migrate-dotnet-to-isolated-model?tabs=net8#trigger-and-binding-changes). |
| 82 | + |
| 83 | +### Trigger function signature and logic |
| 84 | + |
| 85 | +- Change `ExecutionContext` parameter to `FunctionContext` |
| 86 | +- The logger can be accessed through the `FunctionContext` |
| 87 | +- The `functionEndpoint.Send` method no longer takes the logger as a parameter. |
| 88 | +- Update the trigger function annotation from `[FunctionName(<triggerFunctionName>)` to `[Function(<triggerFunctionName>)]` |
| 89 | + |
| 90 | +An example of an in-process trigger function |
| 91 | + |
| 92 | +```csharp |
| 93 | + public class HttpSender |
| 94 | + { |
| 95 | + readonly IFunctionEndpoint functionEndpoint; |
| 96 | + |
| 97 | + public HttpSender(IFunctionEndpoint functionEndpoint) |
| 98 | + { |
| 99 | + this.functionEndpoint = functionEndpoint; |
| 100 | + } |
| 101 | + |
| 102 | + [FunctionName("HttpSender")] |
| 103 | + public async Task<IActionResult> Run( |
| 104 | + [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest request, ExecutionContext executionContext, ILogger logger) |
| 105 | + { |
| 106 | + logger.LogInformation("C# HTTP trigger function received a request."); |
| 107 | + |
| 108 | + var sendOptions = new SendOptions(); |
| 109 | + sendOptions.RouteToThisEndpoint(); |
| 110 | + |
| 111 | + await functionEndpoint.Send(new TriggerMessage(), sendOptions, executionContext, logger); |
| 112 | + |
| 113 | + return new OkObjectResult($"{nameof(TriggerMessage)} sent."); |
| 114 | + } |
| 115 | + } |
| 116 | +``` |
| 117 | + |
| 118 | +This is an example of a trigger function migrated to the isolated worker model |
| 119 | + |
| 120 | +```csharp |
| 121 | +class HttpSender |
| 122 | +{ |
| 123 | + readonly IFunctionEndpoint functionEndpoint; |
| 124 | + |
| 125 | + public HttpSender(IFunctionEndpoint functionEndpoint) |
| 126 | + { |
| 127 | + this.functionEndpoint = functionEndpoint; |
| 128 | + } |
| 129 | + |
| 130 | + [Function("HttpSender")] |
| 131 | + public async Task<HttpResponseData> Run( |
| 132 | + [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestData req, |
| 133 | + FunctionContext functionContext) |
| 134 | + { |
| 135 | + var logger = functionContext.GetLogger<HttpSender>(); |
| 136 | + logger.LogInformation("C# HTTP trigger function received a request."); |
| 137 | + |
| 138 | + var sendOptions = new SendOptions(); |
| 139 | + sendOptions.RouteToThisEndpoint(); |
| 140 | + |
| 141 | + await functionEndpoint.Send(new TriggerMessage(), sendOptions, functionContext); |
| 142 | + |
| 143 | + var r = req.CreateResponse(HttpStatusCode.OK); |
| 144 | + await r.WriteStringAsync($"{nameof(TriggerMessage)} sent."); |
| 145 | + return r; |
| 146 | + } |
| 147 | +} |
| 148 | +``` |
0 commit comments