Freigeben über


Migrieren von In-Process zum Isolierten Worker-Modell

In diesem Handbuch wird gezeigt, wie Sie Ihre Durable Functions Anwendung aus dem In-Process-Modell zum isolierten Workermodell migrieren.

Warnung

Die Unterstützung für das In-Process-Modell endet am 10. November 2026. Migrieren Sie zum isolierten Workermodell, um weiterhin Unterstützung und Zugriff auf neue Features zu erhalten.

Warum migrieren?

Ende des Supports für das Prozessmodell

Microsoft hat angekündigt, dass das In-Process-Modell für .NET Azure Functions am 10. November 2026 das Ende des Supports erreicht. Nach diesem Datum:

  • Es werden keine Sicherheitsupdates bereitgestellt.
  • Es werden keine Fehlerbehebungen veröffentlicht.
  • Neue Features sind nur im isolierten Arbeitsmodell verfügbar.

Vorteile des isolierten Workermodells

Die Migration zum isolierten Arbeitsmodell bietet die folgenden Vorteile:

Nutzen Beschreibung
Keine Assemblykonflikte Ihr Code wird in einem separaten Prozess ausgeführt, wodurch Versionskonflikte beseitigt werden.
Vollständige Prozesskontrolle Steuern des Starts, der Konfiguration und der Middleware über Program.cs
Standard-DI-Muster Vertraute .NET Abhängigkeitsinjektion verwenden
.NET-Versionsflexibilität Unterstützung für LTS, STS und .NET Framework
Middleware-Unterstützung Vollständige ASP.NET Core Middlewarepipeline
Bessere Leistung ASP.NET Core Integration für HTTP-Trigger
Plattformunterstützung Zugriff auf Flex-Verbrauchsplan und .NET Aspire

Voraussetzungen

Bevor Sie die Migration starten, stellen Sie sicher, dass Sie über die folgenden Voraussetzungen verfügen:

  • Azure Functions Core Tools v4.x oder höher
  • .NET 8.0 SDK (oder Die Zielversion .NET)
  • Visual Studio 2022 oder VS-Code mit Azure Functions Erweiterung
  • Vertrautheit mit Durable Functions Konzepten

Übersicht zur Migration

Der Migrationsprozess umfasst die folgenden Hauptschritte:

  1. Identifizieren der zu migrierenden Apps
  2. Aktualisieren der Projektdatei
  3. Hinzufügen von Program.cs
  4. Aktualisieren von Paketverweise
  5. Funktionscode aktualisieren
  6. Aktualisieren von local.settings.json
  7. Lokal testen
  8. Deploy to Azure

Identifizieren der zu migrierenden Apps

Verwenden Sie dieses Azure PowerShell Skript, um Funktions-Apps in Ihrem Abonnement zu finden, die das In-Process-Modell verwenden:

$FunctionApps = Get-AzFunctionApp

$AppInfo = @{}

foreach ($App in $FunctionApps)
{
     if ($App.Runtime -eq 'dotnet')
     {
          $AppInfo.Add($App.Name, $App.Runtime)
     }
}

$AppInfo

Apps, die dotnet als Laufzeit verwenden, nutzen das In-Process-Modell. Apps, die dotnet-isolated verwenden, nutzen bereits das isolierte Workermodell.

Aktualisieren der Projektdatei

Vorher (im Prozess)

<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>

Nach (Isolierter Arbeiter)

<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>

Die wichtigsten Änderungen

  • Hinzufügen <OutputType>Exe</OutputType> – Der isolierte Worker ist eine ausführbare Datei.
  • Hinzufügen von <FrameworkReference Include="Microsoft.AspNetCore.App" /> – Für ASP.NET Core Integration
  • Ersetzen Sie Microsoft.NET.Sdk.Functions durch Microsoft.Azure.Functions.Worker.*Pakete
  • Ersetzen Sie Microsoft.Azure.WebJobs.Extensions.DurableTask durch Microsoft.Azure.Functions.Worker.Extensions.DurableTask

Hinzufügen von Program.cs

Erstellen Sie eine neue Program.cs Datei im Projektstamm:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services => {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
    })
    .Build();

host.Run();

Mit benutzerdefinierten Diensten

Wenn Sie eine FunctionsStartup Klasse hatten, verschieben Sie diese Konfiguration in Program.cs:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services => {
        // Application Insights
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
        
        // Your custom services (previously in FunctionsStartup)
        services.AddSingleton<IMyService, MyService>();
        services.AddHttpClient<IApiClient, ApiClient>();
    })
    .Build();

host.Run();

FunctionsStartup löschen

Wenn Sie ein Startup.cs mit [assembly: FunctionsStartup(...)] haben, löschen Sie es, nachdem Sie die Konfiguration in Program.cs verschoben haben.

Aktualisieren von Paketverweise

Durable Functions Paket-Änderungen

In-Process-Paket Isoliertes Arbeitspaket
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

Allgemeine Änderungen des Erweiterungspakets

In Bearbeitung Eingeschlossener Mitarbeiter
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

Von Bedeutung

Entfernen Sie alle Verweise auf Microsoft.Azure.WebJobs.* Namespaces und Microsoft.Azure.Functions.Extensions aus Ihrem Projekt.

Funktionscode aktualisieren

Namespaceänderungen

// 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;

Funktionsattributeänderungen

// Before (In-Process)
[FunctionName("MyOrchestrator")]

// After (Isolated Worker)
[Function(nameof(MyOrchestrator))]

Orchestrator-Funktionsänderungen

Vorher (In-Prozess):

[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 };
}

Nach (Isolierter Arbeiter):

[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 };
}

Wichtige Unterschiede

Aspekt In Bearbeitung Isolierter Worker
Kontexttyp IDurableOrchestrationContext TaskOrchestrationContext
Logger ILogger Parameter context.CreateReplaySafeLogger()
Merkmal [FunctionName] [Function]

Änderungen der Aktivitätsfunktion

Vorher (In-Prozess):

[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;
}

After (Isolierter Arbeiter):

[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;
}

Clientfunktionsänderungen

Vorher (In-Prozess):

[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);
}

Nach (isolierter Arbeiter):

[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);
}

Clienttypänderungen

In Bearbeitung Eingeschlossener Mitarbeiter
IDurableOrchestrationClient DurableTaskClient
StartNewAsync() ScheduleNewOrchestrationInstanceAsync()
CreateCheckStatusResponse() CreateCheckStatusResponseAsync()
HttpRequest / IActionResult HttpRequestData / HttpResponseData

Erneutes Wiederholen von Richtlinienänderungen

Bei der Verarbeitung werden RetryOptions mit CallActivityWithRetryAsync verwendet. Der isolierte Worker verwendet TaskOptions mit dem Standard CallActivityAsync.

Vorher (in Bearbeitung):

var retryOptions = new RetryOptions(
    firstRetryInterval: TimeSpan.FromSeconds(5),
    maxNumberOfAttempts: 3);

string result = await context.CallActivityWithRetryAsync<string>(
    "MyActivity", retryOptions, input);

Nach (isolierter Arbeiter):

var retryOptions = new TaskOptions(
    new TaskRetryOptions(new RetryPolicy(
        maxNumberOfAttempts: 3,
        firstRetryInterval: TimeSpan.FromSeconds(5))));

string result = await context.CallActivityAsync<string>(
    "MyActivity", input, retryOptions);

Änderungen der Entitätsfunktion

Vorher (In Bearbeitung):

[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;
    }
}

After (Isolierter Arbeiter):

[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;
}

Vollständige API-Referenz

Die folgenden Tabellen enthalten eine umfassende Zuordnung zwischen dem In-Process 2.x SDK und den isolierten Worker-SDK-APIs.

Client-APIs

Prozessintern (Version 2.x) Eingeschlossener Mitarbeiter
IDurableOrchestrationClient DurableTaskClient
IDurableOrchestrationClient.StartNewAsync DurableTaskClient.ScheduleNewOrchestrationInstanceAsync
IDurableOrchestrationClient.GetStatusAsync DurableTaskClient.GetInstanceAsync
IDurableOrchestrationClient.ListInstancesAsync DurableTaskClient.GetAllInstancesAsync
IDurableOrchestrationClient.TerminateAsync DurableTaskClient.TerminateInstanceAsync
IDurableOrchestrationClient.SuspendAsync DurableTaskClient.SuspendInstanceAsync
IDurableOrchestrationClient.ResumeAsync DurableTaskClient.ResumeInstanceAsync
IDurableOrchestrationClient.RaiseEventAsync DurableTaskClient.RaiseEventAsync
IDurableOrchestrationClient.RewindAsync DurableTaskClient.RewindInstanceAsync
IDurableOrchestrationClient.RestartAsync DurableTaskClient.RestartAsync
IDurableOrchestrationClient.PurgeInstanceHistoryAsync DurableTaskClient.PurgeInstanceAsync oder PurgeAllInstancesAsync
IDurableOrchestrationClient.CreateCheckStatusResponse DurableTaskClient.CreateCheckStatusResponseAsync (Erweiterungsmethode, nimmt HttpRequestData)
IDurableOrchestrationClient.WaitForCompletionOrCreateCheckStatusResponseAsync DurableTaskClient.WaitForCompletionOrCreateCheckStatusResponseAsync (Erweiterungsmethode, timeout ersetzt durch CancellationToken)
IDurableOrchestrationClient.CreateHttpManagementPayload DurableTaskClient.CreateHttpManagementPayload (Erweiterungsmethode)
IDurableOrchestrationClient.MakeCurrentAppPrimaryAsync Entfernt
IDurableOrchestrationClient.GetStatusAsync(IEnumerable<string>) Entfernt Verwenden Sie GetInstanceAsync in einer Schleife oder GetAllInstancesAsync mit einem Abfragefilter.
IDurableOrchestrationClient.PurgeInstanceHistoryAsync(IEnumerable<string>) Entfernt Benutzen Sie PurgeInstanceAsync in einer Schleife oder PurgeAllInstancesAsync mit einem Filter.
IDurableOrchestrationClient.RaiseEventAsync (Überlastung des Cross-Task-Hubs mit taskHubName) Entfernt Nur das Auslösen von Ereignissen im gleichen Aufgabenhub wird unterstützt.
IDurableEntityClient.SignalEntityAsync DurableTaskClient.Entities.SignalEntityAsync
IDurableEntityClient.SignalEntityAsync (Überlastung des Cross-Task-Hubs mit taskHubName, connectionName) Entfernt Es werden nur Vorgänge von Entitäten im gleichen Aufgabenhub unterstützt.
IDurableEntityClient.ReadEntityStateAsync DurableTaskClient.Entities.GetEntityAsync
IDurableEntityClient.ReadEntityStateAsync (Cross-Task-Hub-Überlastung mit taskHubName, connectionName) Entfernt Es werden nur Vorgänge von Entitäten im gleichen Aufgabenhub unterstützt.
IDurableEntityClient.ListEntitiesAsync DurableTaskClient.Entities.GetAllEntitiesAsync
IDurableEntityClient.CleanEntityStorageAsync DurableTaskClient.Entities.CleanEntityStorageAsync (verwendet CleanEntityStorageRequest Objekt anstelle von Bool-Parametern)
DurableOrchestrationStatus OrchestrationMetadata
DurableOrchestrationStatus.History Aus statusobjekt entfernt. Verwenden Sie stattdessen DurableTaskClient.GetOrchestrationHistoryAsync.
PurgeHistoryResult PurgeResult
OrchestrationStatusQueryCondition OrchestrationQuery
OrchestrationStatusQueryResult AsyncPageable<OrchestrationMetadata>

Orchestrierungskontext-APIs

Prozessintern (Version 2.x) Eingeschlossener Mitarbeiter
IDurableOrchestrationContext TaskOrchestrationContext
IDurableOrchestrationContext.GetInput<T>() TaskOrchestrationContext.GetInput<T>() oder Einfügen von Eingaben als Parameter: MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context, T input)
IDurableOrchestrationContext.SetOutput Entfernt Verwenden Sie den Rückgabewert aus der Orchestratorfunktion.
IDurableOrchestrationContext.CallActivityWithRetryAsync TaskOrchestrationContext.CallActivityAsync mit einem TaskOptions Parameter für Wiederholungsdetails.
IDurableOrchestrationContext.CallSubOrchestratorWithRetryAsync TaskOrchestrationContext.CallSubOrchestratorAsync mit einem Parameter TaskOptions für Wiederholungsdetails.
IDurableOrchestrationContext.CallHttpAsync TaskOrchestrationContext.CallHttpAsync
IDurableOrchestrationContext.CreateTimer<T>(DateTime, T, CancellationToken) TaskOrchestrationContext.CreateTimer(DateTime, CancellationToken). Zustandsparameter entfernt.
IDurableOrchestrationContext.WaitForExternalEvent(string) (nicht generisch) Entfernt Verwenden Sie WaitForExternalEvent<T>(string, CancellationToken).
IDurableOrchestrationContext.WaitForExternalEvent<T>(string, TimeSpan, T) (mit defaultValue) Entfernt Verwenden Sie WaitForExternalEvent<T>(string, TimeSpan, CancellationToken), die bei einem Timeout TaskCanceledException auslöst.
IDurableOrchestrationContext.ParentInstanceId TaskOrchestrationContext.Parent.InstanceId
IDurableOrchestrationContext.CreateReplaySafeLogger(ILogger) TaskOrchestrationContext.CreateReplaySafeLogger<T>() oder TaskOrchestrationContext.CreateReplaySafeLogger(string)
IDurableOrchestrationContext.CreateEntityProxy<T> Entfernt Verwenden Sie Entities.CallEntityAsync oder Entities.SignalEntityAsync direkt.
IDurableOrchestrationContext.CallEntityAsync TaskOrchestrationContext.Entities.CallEntityAsync
IDurableOrchestrationContext.SignalEntity TaskOrchestrationContext.Entities.SignalEntityAsync
IDurableOrchestrationContext.LockAsync TaskOrchestrationContext.Entities.LockEntitiesAsync
IDurableOrchestrationContext.IsLocked TaskOrchestrationContext.Entities.InCriticalSection()
RetryOptions TaskOptions mit TaskRetryOptions
DurableActivityContext Keine Entsprechung
DurableActivityContext.GetInput<T>() Einfügen von Eingaben als Parameter: MyActivity([ActivityTrigger] T input)
DurableHttpRequest (WebJobs-Namespace) DurableHttpRequest (Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Http-Namespace)
DurableHttpResponse (WebJobs-Namespace) DurableHttpResponse (Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Http-Namespace)

Entitäts-APIs

Prozessintern (Version 2.x) Eingeschlossener Mitarbeiter
IDurableEntityContext TaskEntityContext
IDurableEntityContext.EntityName TaskEntityContext.Id.Name
IDurableEntityContext.EntityKey TaskEntityContext.Id.Key
IDurableEntityContext.OperationName TaskEntityOperation.Name
IDurableEntityContext.FunctionBindingContext Entfernt Als Eingabeparameter hinzufügen FunctionContext .
IDurableEntityContext.HasState TaskEntityOperation.State.HasState
IDurableEntityContext.GetState TaskEntityOperation.State.GetState
IDurableEntityContext.SetState TaskEntityOperation.State.SetState
IDurableEntityContext.DeleteState TaskEntityOperation.State.SetState(null)
IDurableEntityContext.GetInput TaskEntityOperation.GetInput
IDurableEntityContext.Return Entfernt Verwenden Sie stattdessen den Rückgabewert der Methode.
IDurableEntityContext.SignalEntity TaskEntityContext.SignalEntity. Geplante Signale verwenden SignalEntityOptions.SignalTime anstelle einer Parameterüberladung DateTime.
IDurableEntityContext.StartNewOrchestration TaskEntityContext.ScheduleNewOrchestration. Die Instanz-ID wird über StartOrchestrationOptions.InstanceId und nicht über einen Zeichenfolgenparameter festgelegt.
IDurableEntityContext.DispatchAsync TaskEntityDispatcher.DispatchAsync. Konstruktorparameter entfernt; Verwenden Sie stattdessen Standard-DI.
IDurableEntityContext.BatchSize Entfernt
IDurableEntityContext.BatchPosition Entfernt

Änderungen des Verhaltens

Warnung

ContinueAsNew Standardänderung: Der Standardwert des preserveUnprocessedEvents-Parameters wurde von false (2.x) auf true (isolated) geändert. Wenn Ihre Orchestrierung ContinueAsNew verwendet und sich darauf stützt, dass unverarbeitete Ereignisse verworfen werden, übergeben Sie preserveUnprocessedEvents: false explizit.

Hinweis

RestartAsync-Standardänderung: Der restartWithNewInstanceId Parameterstandard wurde von true (2.x) in false (isoliert) geändert. Wenn Ihr Code RestartAsync aufruft und von einer neuen, generierten Instanz-ID abhängt, übergeben Sie restartWithNewInstanceId: true explizit.

  • Entfernung des Entitätsproxys: CreateEntityProxy<T> Und die typierten SignalEntityAsync<TEntityInterface>(Action<T>) Delegatüberladungen sind im isolierten Worker nicht verfügbar. Rufen Sie Entities.CallEntityAsync oder Entities.SignalEntityAsync direkt mit Zeichenfolgenbasierten Vorgangsnamen auf, anstatt eingegebene Proxyschnittstellen zu verwenden.
  • WaitForCompletionOrCreateCheckStatusResponseAsync: Der timeout Parameter wurde entfernt. Verwenden Sie stattdessen ein Abbruch-Timeout mit CancellationToken.
  • Aufgabenübergreifende Vorgänge wurden entfernt: Die In-Process-Überladungen, die die taskHubName und connectionName Parameter akzeptierten (bei RaiseEventAsync, SignalEntityAsync und ReadEntityStateAsync), sind in isolierten Workern nicht verfügbar. Es werden nur Vorgänge desselben Task-Hubs unterstützt.
  • Batchvorgänge nach ID entfernt: Die im Prozess GetStatusAsync(IEnumerable<string>)- und PurgeInstanceHistoryAsync(IEnumerable<string>)-Überladungsfunktionen sind in isolierten Arbeitern nicht verfügbar. Verwenden Sie GetAllInstancesAsync mit einem OrchestrationQuery-Filter oder rufen Sie GetInstanceAsync/PurgeInstanceAsync einzeln auf.PurgeInstanceAsync
  • Der Orchestrierungsverlauf wurde verschoben: DurableOrchestrationStatus.History (eingebettet JArray) ist nicht mehr Teil des Statusobjekts. Verwenden Sie die separate DurableTaskClient.GetOrchestrationHistoryAsync API zum Abrufen des Orchestrierungsverlaufs.
  • Entity DispatchAsync-Konstruktorparameter entfernt: Die DispatchAsync<T>(params object[]) Konstruktorparameterüberladung ist nicht verfügbar. Entitätsklassen werden über die Standardmäßige Abhängigkeitsinjektion aktiviert. Registrieren Sie die Abhängigkeiten Ihrer Entität in Program.cs.
  • Änderungen des Entitätsabfragefilters: EntityQuery.EntityName wird durch EntityQuery.InstanceIdStartsWith ersetzt und EntityQuery.IncludeDeleted wird durch EntityQuery.IncludeTransient ersetzt.
  • CleanEntityStorageAsync-Signaturänderung: Anstelle der (bool removeEmptyEntities, bool releaseOrphanedLocks, CancellationToken)isolierten Version wird ein CleanEntityStorageRequest Objekt mit RemoveEmptyEntities und ReleaseOrphanedLocks Eigenschaften verwendet.
  • Neue APIs im isolierten Worker: DurableTaskClient.GetOrchestrationHistoryAsync Und die TaskOrchestrationContext.GetFunctionContext() Erweiterungsmethode ist im isolierten Worker verfügbar, hat jedoch keine In-Process-Entsprechung.

Aktualisieren von local.settings.json

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
        "DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "Endpoint=http://localhost:8080;Authentication=None"
    }
}

Die Schlüsseländerung erfolgt FUNCTIONS_WORKER_RUNTIME von dotnet zu dotnet-isolated.

Lokal testen

Starten des Emulators

docker run -d -p 8080:8080 -p 8082:8082 mcr.microsoft.com/dts/dts-emulator:latest

Führen Sie die Funktions-App aus

func start

Überprüfen der Funktionalität

Testen Sie alle Ihre Orchestrierungen, Aktivitäten und Entitäten, um sicherzustellen, dass sie ordnungsgemäß funktionieren:

  1. Starten einer Orchestrierung mit einem HTTP-Trigger
  2. Überwachen des Orchestrierungsstatus
  3. Überprüfen der Ausführungsreihenfolge der Aktivität
  4. Testen von Entitätsvorgängen, falls zutreffend
  5. Überprüfen Sie die Telemetrie von Application Insights

Bereitstellen auf Azure

Verwenden Sie Bereitstellungsplätze, um Ausfallzeiten zu minimieren:

  1. Erstellen Sie einen Staging-Slot für Ihre Funktions-App.
  2. Konfiguration des Stagingplatzes aktualisieren:
    • Setzen Sie FUNCTIONS_WORKER_RUNTIME auf dotnet-isolated.
    • Aktualisieren Sie die .NET-Stackversion falls erforderlich.
  3. Stellen Sie migrierten Code im Staging-Slot bereit.
  4. Testen Sie gründlich im Staging-Slot.
  5. Durchführen eines Slottauschs um Änderungen in die Produktion zu übertragen.

Aktualisieren von Anwendungseinstellungen

Im Azure Portal oder über CLI:

az functionapp config appsettings set \
    --name <FUNCTION_APP_NAME> \
    --resource-group <RESOURCE_GROUP> \
    --settings FUNCTIONS_WORKER_RUNTIME=dotnet-isolated

Aktualisierung der Stapelkonfiguration

Wenn sie auf eine andere .NET Version ausgerichtet sind:

az functionapp config set \
    --name <FUNCTION_APP_NAME> \
    --resource-group <RESOURCE_GROUP> \
    --net-framework-version v8.0

Häufige Probleme bei der Migration

Problem: Assemblyladefehler

Symptom:Could not load file or assembly Fehler.

Solution: Stellen Sie sicher, dass Sie alle Microsoft.Azure.WebJobs.* Paketverweise entfernen und durch isolierte Workerentsprechungen ersetzen.

Problem: Das Bindungsattribut wurde nicht gefunden.

Symptom:The type or namespace 'QueueTrigger' could not be found

Lösung: Fügen Sie das entsprechende Erweiterungspaket hinzu, und aktualisieren Sie mithilfe von Anweisungen:

// Add using statement
using Microsoft.Azure.Functions.Worker;

// Install package
// dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues

Problem: IDurableOrchestrationContext nicht gefunden

Symptom:The type or namespace 'IDurableOrchestrationContext' could not be found

Lösung: Ersetzen durch TaskOrchestrationContext:

using Microsoft.DurableTask;

[Function(nameof(MyOrchestrator))]
public static async Task MyOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context)
{
    // ...
}

Problem: Unterschiede bei der JSON-Serialisierung

Symptom: Serialisierungsfehler oder unerwartete Datenformate

Lösung: Das isolierte Modell verwendet System.Text.Json standardmäßig. Serialisierung konfigurieren in Program.cs:

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services => {
        services.Configure<JsonSerializerOptions>(options => {
            options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
        });
    })
    .Build();

So verwenden Sie stattdessen Newtonsoft.Json:

services.Configure<WorkerOptions>(options => {
    options.Serializer = new NewtonsoftJsonObjectSerializer();
});

Problem: Migrieren von benutzerdefinierten Serialisierungseinstellungen

Symptom: Sie haben IMessageSerializerSettingsFactory im In-Process-Modell die JSON-Serialisierung für Orchestrierungseingaben, Ausgaben oder den Entitätsstatus angepasst und benötigen das Äquivalent in einem isolierten Worker.

Lösung: Die IMessageSerializerSettingsFactory Schnittstelle ist in isolierten Workern nicht verfügbar. Konfigurieren Sie stattdessen den Serialisierer auf Arbeitsebene in Program.cs:

Vor (in Bearbeitung)

// Startup.cs
[assembly: FunctionsStartup(typeof(MyStartup))]
public class MyStartup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddSingleton<IMessageSerializerSettingsFactory, CustomSerializerSettingsFactory>();
    }
}

Nach (Isolierter Arbeiter):

// 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();

Hinweis

Für diesen Ansatz sind die Newtonsoft.Json und Azure.Core.Serialization NuGet-Pakete erforderlich. Die Einstellung WorkerOptions.Serializer gilt global für alles, was von der erweiterung Durable Functions serialisiert wird. Weitere Informationen finden Sie unter Serialisierung und Persistenz in Durable Functions.

Checklist

Verwenden Sie diese Checkliste, um eine vollständige Migration sicherzustellen:

  • Aktualisierte Projektdatei mit <OutputType>Exe</OutputType>
  • Microsoft.NET.Sdk.Functions durch Arbeitspakete ersetzt
  • Microsoft.Azure.WebJobs.Extensions.DurableTask durch isoliertes Paket ersetzt
  • Mit Hostkonfiguration erstellt Program.cs
  • Klasse FunctionsStartup entfernt (sofern vorhanden)
  • Alle [FunctionName] aktualisiert auf [Function]
  • Ersetzt IDurableOrchestrationContext durch TaskOrchestrationContext
  • Ersetzt IDurableOrchestrationClient durch DurableTaskClient
  • Aktualisierte Protokollierung für die Verwendung von DI oder FunctionContext
  • Aktualisiert local.settings.json mit dotnet-isolated Laufzeit
  • Alle Microsoft.Azure.WebJobs.* using-Anweisungen entfernt
  • Using-Anweisungen Microsoft.Azure.Functions.Worker hinzugefügt
  • Ersetzt CreateEntityProxy<T> durch direkte CallEntityAsync/SignalEntityAsync Anrufe
  • Ersetzte Cross-Task-Hub-Betriebsüberladungen (falls verwendet)
  • Batch- GetStatusAsync/PurgeInstanceHistoryAsync by-ID Anrufe durch filterbasierte oder einzelne Anrufe ersetzt
  • Migrierter DurableOrchestrationStatus.History Zugriff auf GetOrchestrationHistoryAsync
  • Aktualisierte Entitätskonstruktorparameter DispatchAsync für die Verwendung von DI
  • Lokales Testen aller Funktionen
  • Bereitgestellt für Staging-Steckplatz und überprüft
  • In die Produktion überführt

Nächste Schritte

Weitere Ressourcen