このガイドでは、.NET Durable Functions アプリをインプロセス モデルから分離ワーカー モデルに移行する手順について説明します。 インプロセス モデルは、 2026 年 11 月 10 日にサポートが終了します。 その日を過ぎると、セキュリティ更新プログラムやバグ修正は提供されません。 分離ワーカー モデルでは、完全なプロセス制御、標準の.NET依存関係の挿入、最新のプラットフォーム機能へのアクセスも提供されます。
Warnung
インプロセス モデルのサポートは 、2026 年 11 月 10 日に終了します。 今すぐ移行することをお勧めします。 分離ワーカー モデルの背景については、「.NET分離ワーカー プロセスの概要を参照してください。
移行チェックリスト
次のチェックリストを使用して、各移行手順の進行状況を追跡します。
| Step | セクション |
|---|---|
| 1. 前提条件を確認する | 前提条件 |
| 2. プロジェクト ファイルを更新する | プロジェクト ファイルを更新する |
| 3. Program.csを追加する | Program.csの追加 |
| 4. パッケージ参照を更新する | パッケージ参照を更新する |
| 5. 関数コードを更新する | 関数コードを更新する |
| 6. local.settings.json を更新する | local.settings.jsonの更新 |
| 7. ローカルでテストする | ローカルでテストする |
| 8. Azureにデプロイする | Azure に配置する |
前提条件
- Azure Functions Core Tools v4.x 以降
- .NET 8.0 SDK (またはターゲット .NET バージョン)
- Visual Studio 2022 または VS Code with Azure Functions extension
移行するアプリを特定する (省略可能)
まだインプロセス モデルを使用しているアプリがわからない場合は、次のAzure PowerShellスクリプトを実行します。
$FunctionApps = Get-AzFunctionApp
$AppInfo = @{}
foreach ($App in $FunctionApps)
{
if ($App.Runtime -eq 'dotnet')
{
$AppInfo.Add($App.Name, $App.Runtime)
}
}
$AppInfo
ランタイムとして dotnet を表示するアプリは、インプロセス モデルを使用します。
dotnet-isolatedを表示するアプリでは、分離された worker モデルが既に使用されています。
プロジェクト ファイルを更新する
進行中(途中段階)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.13.0" />
</ItemGroup>
</Project>
その後 (分離ワーカー)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.2.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.14.1" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext"/>
</ItemGroup>
</Project>
主な変更は、実行可能な出力の種類に切り替え、すべてのMicrosoft.Azure.WebJobs.* パッケージを、Microsoft.Azure.Functions.Worker.* 同等のパッケージに置き換えることです。
Program.csの追加
分離ワーカー モデルには、 Program.cs エントリ ポイントが必要です。 プロジェクト ルートにこのファイルを作成します。
FunctionsStartupにStartup.cs クラスがある場合は、それらのサービス登録を ConfigureServices ブロックに移動し、Startup.csを削除します。
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
// Add your custom services here (previously in FunctionsStartup)
// services.AddSingleton<IMyService, MyService>();
})
.Build();
host.Run();
パッケージ参照を更新する
Durable Functions パッケージ のマッピング
| インプロセス パッケージ | 分離ワーカー パッケージ |
|---|---|
Microsoft.Azure.WebJobs.Extensions.DurableTask |
Microsoft.Azure.Functions.Worker.Extensions.DurableTask |
Microsoft.DurableTask.SqlServer.AzureFunctions |
Microsoft.Azure.Functions.Worker.Extensions.DurableTask.SqlServer |
Microsoft.Azure.DurableTask.Netherite.AzureFunctions |
Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Netherite |
一般的な拡張機能パッケージのマッピング
| 進行中 | アイソレートワーカー |
|---|---|
Microsoft.Azure.WebJobs.Extensions.Storage |
Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs、.Queues、.Tables |
Microsoft.Azure.WebJobs.Extensions.CosmosDB |
Microsoft.Azure.Functions.Worker.Extensions.CosmosDB |
Microsoft.Azure.WebJobs.Extensions.ServiceBus |
Microsoft.Azure.Functions.Worker.Extensions.ServiceBus |
Microsoft.Azure.WebJobs.Extensions.EventHubs |
Microsoft.Azure.Functions.Worker.Extensions.EventHubs |
Microsoft.Azure.WebJobs.Extensions.EventGrid |
Microsoft.Azure.Functions.Worker.Extensions.EventGrid |
Important
Microsoft.Azure.WebJobs.* 名前空間と Microsoft.Azure.Functions.Extensions への参照をプロジェクトから削除します。
関数コードを更新する
このセクションでは、各Durable Functionsの種類のコード変更について説明します。 アプリで使用する関数の種類のセクションに移動します。
API ごとの完全なマッピングについては、 API リファレンスを参照してください。
名前空間の変更
// Before (In-Process)
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.Http;
// After (Isolated Worker)
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.DurableTask.Entities;
関数属性の変更
// Before (In-Process)
[FunctionName("MyOrchestrator")]
// After (Isolated Worker)
[Function(nameof(MyOrchestrator))]
オーケストレーター関数の変更
以前(進行中):
[FunctionName("OrderOrchestrator")]
public static async Task<OrderResult> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context,
ILogger log)
{
var order = context.GetInput<Order>();
await context.CallActivityAsync("ValidateOrder", order);
await context.CallActivityAsync("ProcessPayment", order.Payment);
await context.CallActivityAsync("ShipOrder", order);
return new OrderResult { Success = true };
}
アフター(アイソレーテッドワーカー):
[Function(nameof(OrderOrchestrator))]
public static async Task<OrderResult> OrderOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
ILogger logger = context.CreateReplaySafeLogger(nameof(OrderOrchestrator));
var order = context.GetInput<Order>();
await context.CallActivityAsync("ValidateOrder", order);
await context.CallActivityAsync("ProcessPayment", order.Payment);
await context.CallActivityAsync("ShipOrder", order);
return new OrderResult { Success = true };
}
主な違い
| 特徴 | 処理中 | 孤立作業者 |
|---|---|---|
| コンテキストの種類 | IDurableOrchestrationContext |
TaskOrchestrationContext |
| Logger |
ILogger パラメーター |
context.CreateReplaySafeLogger() |
| 特性 | [FunctionName] |
[Function] |
アクティビティ関数の変更
以前(進行中):
[FunctionName("ValidateOrder")]
public static bool ValidateOrder(
[ActivityTrigger] Order order,
ILogger log)
{
log.LogInformation("Validating order {OrderId}", order.Id);
return order.Items.Any() && order.TotalAmount > 0;
}
アフター(アイソレーテッドワーカー):
[Function(nameof(ValidateOrder))]
public static bool ValidateOrder(
[ActivityTrigger] Order order,
FunctionContext executionContext)
{
ILogger logger = executionContext.GetLogger(nameof(ValidateOrder));
logger.LogInformation("Validating order {OrderId}", order.Id);
return order.Items.Any() && order.TotalAmount > 0;
}
クライアント関数の変更
以前(進行中):
[FunctionName("StartOrder")]
public static async Task<IActionResult> StartOrder(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
[DurableClient] IDurableOrchestrationClient client,
ILogger log)
{
var order = await req.ReadFromJsonAsync<Order>();
string instanceId = await client.StartNewAsync("OrderOrchestrator", order);
return client.CreateCheckStatusResponse(req, instanceId);
}
アフター(アイソレーテッドワーカー):
[Function("StartOrder")]
public static async Task<HttpResponseData> StartOrder(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
[DurableClient] DurableTaskClient client,
FunctionContext executionContext)
{
ILogger logger = executionContext.GetLogger("StartOrder");
var order = await req.ReadFromJsonAsync<Order>();
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(
nameof(OrderOrchestrator),
order
);
return await client.CreateCheckStatusResponseAsync(req, instanceId);
}
クライアントの種類の変更
| 進行中 | アイソレートワーカー |
|---|---|
IDurableOrchestrationClient |
DurableTaskClient |
StartNewAsync() |
ScheduleNewOrchestrationInstanceAsync() |
CreateCheckStatusResponse() |
CreateCheckStatusResponseAsync() |
HttpRequest / IActionResult |
HttpRequestData / HttpResponseData |
ポリシーの変更を再試行する
インプロセスはRetryOptionsとCallActivityWithRetryAsyncを使用します。 分離ワーカーは、TaskOptionsと標準のCallActivityAsyncを使用します。
以前(進行中):
var retryOptions = new RetryOptions(
firstRetryInterval: TimeSpan.FromSeconds(5),
maxNumberOfAttempts: 3);
string result = await context.CallActivityWithRetryAsync<string>(
"MyActivity", retryOptions, input);
アフター(アイソレーテッドワーカー):
var retryOptions = new TaskOptions(
new TaskRetryOptions(new RetryPolicy(
maxNumberOfAttempts: 3,
firstRetryInterval: TimeSpan.FromSeconds(5))));
string result = await context.CallActivityAsync<string>(
"MyActivity", input, retryOptions);
エンティティ関数の変更
以前(進行中):
[FunctionName(nameof(Counter))]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
switch (ctx.OperationName.ToLowerInvariant())
{
case "add":
ctx.SetState(ctx.GetState<int>() + ctx.GetInput<int>());
break;
case "get":
ctx.Return(ctx.GetState<int>());
break;
}
}
アフター(アイソレーテッドワーカー):
[Function(nameof(Counter))]
public static Task Counter([EntityTrigger] TaskEntityDispatcher dispatcher)
{
return dispatcher.DispatchAsync<CounterEntity>();
}
public class CounterEntity
{
public int Value { get; set; }
public void Add(int amount) => Value += amount;
public int Get() => Value;
}
破壊的動作の変更
移行したアプリをテストする前に、これらの変更を確認してください。 API ごとの完全なマッピングについては、 API リファレンスを参照してください。
Warnung
シリアル化の既定の変更: 分離されたワーカーは、System.Text.Jsonの代わりに既定でNewtonsoft.Jsonを使用します。 オーケストレーションで複雑なオブジェクトを渡す場合は、シリアル化を慎重にテストしてください。 構成オプションについては、 JSON シリアル化の違い を参照してください。
Warnung
ContinueAsNew の既定の変更: preserveUnprocessedEvents パラメーターの既定値が false (2.x) から true (分離) に変更されました。 オーケストレーションで ContinueAsNew を使用し、破棄される未処理のイベントに依存している場合は、 preserveUnprocessedEvents: falseを明示的に渡します。
注
RestartAsync の既定の変更: restartWithNewInstanceId パラメーターの既定値が true (2.x) から false (分離) に変更されました。 コードが RestartAsync を呼び出し、生成される新しいインスタンス ID に依存している場合は、 restartWithNewInstanceId: trueを明示的に渡します。
その他の重要な変更点:
-
エンティティ プロキシが削除されました 。
CreateEntityProxy<T>は使用できません。Entities.CallEntityAsyncまたはEntities.SignalEntityAsyncを直接使用します。 -
クロスタスクハブ操作が削除されました —
taskHubName/connectionNameを受け入れるオーバーロードは使用できません。 同じタスク ハブ操作のみがサポートされます。 -
オーケストレーション履歴が移動されました 。
DurableOrchestrationStatus.Historyが状態オブジェクトに表示されなくなります。DurableTaskClient.GetOrchestrationHistoryAsyncを使用してください。
local.settings.jsonの更新
主な変更は、FUNCTIONS_WORKER_RUNTIMEからdotnetにdotnet-isolatedを設定することです。
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}
}
注
ストレージ バックエンド構成 (Azure Storage、MSSQL、Netherite、または Durable Task Scheduler) は、移行によって変更されません。 既存のストレージ関連の設定を保持します。
ローカルでテストする
関数アプリをローカルで実行し、すべてのオーケストレーション、アクティビティ、エンティティが正しく動作するかどうかを確認します。
func start
機能を検証する
必要に応じて、次のシナリオをテストします。
- HTTP トリガーを使用してオーケストレーションを開始する
- オーケストレーションの状態を監視する
- アクティビティの実行順序を確認する
- エンティティ操作 (該当する場合) をテストする
- Application Insights テレメトリを確認する
Azure にデプロイ
推奨: デプロイ スロットを使用する
デプロイ スロットを使用してダウンタイムを最小限に抑えます。
- 関数アプリのステージング スロットを作成します。
-
ステージング スロットの構成を更新します。
-
FUNCTIONS_WORKER_RUNTIMEをdotnet-isolatedに設定します。 - 必要に応じて.NETスタック バージョンを更新します。
-
- 移行されたコード をステージング スロットにデプロイします。
- ステージング スロットで十分にテストします。
- スロット スワップを実行 し、変更を本番環境に反映します。
アプリケーション設定を更新する
Azure ポータルまたは CLI を使用して、次の手順を実行します。
az functionapp config appsettings set \
--name <FUNCTION_APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--settings FUNCTIONS_WORKER_RUNTIME=dotnet-isolated
スタックの構成を更新
別の.NET バージョンを対象とする場合:
az functionapp config set \
--name <FUNCTION_APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--net-framework-version v8.0
移行に関する一般的な問題
問題: アセンブリの読み込みエラー
現象:Could not load file or assembly エラー。
ソリューション: すべてのMicrosoft.Azure.WebJobs.* パッケージ参照を削除し、それらを分離ワーカーと同等のものに置き換えます。
問題: バインド属性が見つかりません
症状:The type or namespace 'QueueTrigger' could not be found
ソリューション: 適切な拡張パッケージを追加し、ステートメントを使用して更新します。
// Add using statement
using Microsoft.Azure.Functions.Worker;
// Install package
// dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues
問題: IDurableOrchestrationContext が見つかりません
症状:The type or namespace 'IDurableOrchestrationContext' could not be found
ソリューション:TaskOrchestrationContextに置き換えます。
using Microsoft.DurableTask;
[Function(nameof(MyOrchestrator))]
public static async Task MyOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context)
{
// ...
}
問題: JSON シリアル化の違い
症状: シリアル化エラーまたは予期しないデータ形式
ソリューション: 分離モデルでは、既定で System.Text.Json が使用されます。
Program.csでシリアル化を構成します。
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
services.Configure<JsonSerializerOptions>(options => {
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
})
.Build();
代わりに Newtonsoft.Json を使用するには:
services.Configure<WorkerOptions>(options => {
options.Serializer = new NewtonsoftJsonObjectSerializer();
});
問題: カスタム シリアル化設定の移行
症状: インプロセス モデルで IMessageSerializerSettingsFactory を使用しており、分離ワーカーで同等のものが必要です。
ソリューション:Program.csでワーカー レベルのシリアライザーを構成します。 詳細については、API リファレンスの behavioral changes のセクション と Durable Functions での階層化と永続化を参照してください。
カスタム設定で Newtonsoft.Json を使用するには:
// Program.cs
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
services.Configure<WorkerOptions>(options =>
{
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
};
options.Serializer = new NewtonsoftJsonObjectSerializer(settings);
});
})
.Build();
注
この方法では、Newtonsoft.Json および Azure.Core.Serialization NuGet パッケージが必要です。
Checklist
完全な移行を確認するには、次のチェックリストを使用します。
- プロジェクト ファイルを
<OutputType>Exe</OutputType>で更新しました -
Microsoft.NET.Sdk.Functionsをワーカー パッケージに置き換えた -
Microsoft.Azure.WebJobs.Extensions.DurableTaskを分離パッケージに置き換えました - ホスト構成を使用して
Program.csを作成しました - クラス
FunctionsStartup削除 (存在する場合) - すべての
[FunctionName]を[Function]に更新しました -
IDurableOrchestrationContextに置き換えられましたTaskOrchestrationContext -
IDurableOrchestrationClientに置き換えられましたDurableTaskClient - ログの更新を行い、DI または
FunctionContextを使用する -
local.settings.jsonランタイムを使用してdotnet-isolatedを更新しました - すべての
Microsoft.Azure.WebJobs.*using ステートメントを削除した -
Microsoft.Azure.Functions.Workerusing ステートメントを追加した -
CreateEntityProxy<T>を直接CallEntityAsync/SignalEntityAsync呼び出しに置き換えた - 使用中の場合はタスクハブ間での操作オーバーロードを置き換えました
- バッチ
GetStatusAsync/PurgeInstanceHistoryAsyncby-ID呼び出しをフィルターベースまたは個別の呼び出しに置き換えた -
DurableOrchestrationStatus.HistoryアクセスがGetOrchestrationHistoryAsyncへの移行 - DI を使用するようにエンティティ
DispatchAsyncコンストラクターパラメーターを更新しました - すべての関数をローカルでテストしました
- ステージング スロットにデプロイされ、検証済み
- 運用環境に切り替えた
次のステップ
- インプロセスから分離ワーカー API へのマッピング - 移行のための完全な API リファレンス
- .NET 分離型ワーカー向け Durable Functions の概要
- Durable Functionsバージョンと移行ガイド