Aufgabenhubs in Durable Functions (Azure Functions)

Ein Aufgabenhub in Durable Functions ist eine Darstellung des aktuellen Zustands der Anwendung im Speicher, einschließlich aller ausstehenden Aufgaben. Während eine Funktions-App ausgeführt wird, wird der Fortschritt der Orchestrierungs-, Aktivitäts- und Entitätsfunktionen kontinuierlich im Aufgabenhub gespeichert. Dadurch wird sichergestellt, dass die Anwendung dort fortgesetzt werden kann, wo sie unterbrochen wurde, wenn sie aus irgendeinem Grund vorübergehend beendet oder unterbrochen wurde und daher neu gestartet werden muss. Außerdem ermöglicht dies der Funktions-App, die Computeworker dynamisch zu skalieren.

Diagram showing concept of function app and task hub concept.

Konzeptionell speichert ein Aufgabenhub die folgenden Informationen:

  • Die Instanzzustände aller Orchestrierungs- und Entitätsinstanzen.
  • Die zu verarbeitenden Nachrichten, einschließlich
    • Aktivitätsnachrichten, die Aktivitäten darstellen, die auf die Ausführung warten.
    • Instanznachrichten, die auf die Zustellung an Instanzen warten.

Der Unterschied zwischen Aktivitäts- und Instanznachrichten besteht darin, dass Aktivitätsnachrichten zustandslos sind und somit überall verarbeitet werden können, während Instanznachrichten an eine bestimmte Zustandsinstanz (Orchestrierung oder Entität) übermittelt werden müssen, die durch die Instanz-ID identifiziert wird.

Intern kann jeder Speicheranbieter eine andere Organisation verwenden, um Instanzzustände und Nachrichten darzustellen. Beispielsweise werden Nachrichten in Azure Storage-Warteschlangen vom Azure Storage-Anbieter gespeichert, jedoch in relationalen Tabellen vom MSSQL-Anbieter. Diese Unterschiede sind für die Gestaltung der Anwendung nicht von Bedeutung, aber einige von ihnen können die Leistungsmerkmale beeinflussen. Wir erörtern sie im folgenden Abschnitt Darstellung im Speicher.

Arbeitselemente

Die Aktivitätsnachrichten und Instanznachrichten im Aufgabenhub stellen die Aufgaben dar, die die Funktions-App verarbeiten muss. Während die Funktions-App ausgeführt wird, ruft sie kontinuierlich Arbeitselemente aus dem Aufgabenhub ab. Jedes Arbeitselement verarbeitet mindestens eine Nachricht. Es werden zwei Arten von Arbeitselementen unterschieden:

  • Aktivitätsarbeitselemente: Ausführen einer Aktivitätsfunktion, um eine Aktivitätsnachricht zu verarbeiten.
  • Orchestratorarbeitselemente: Ausführen einer Orchestrator- oder Entitätsfunktion, um mindestens eine Instanznachricht zu verarbeiten.

Worker können mehrere Arbeitselemente gemäß den konfigurierten Pro-Worker-Parallelitätsgrenzwerten gleichzeitig verarbeiten.

Sobald ein Worker ein Arbeitselement abgeschlossen hat, committet er die Effekte zurück an den Aufgabenhub. Diese Effekte unterscheiden sich je nach Funktionstyp, der ausgeführt wurde:

  • Eine abgeschlossene Aktivitätsfunktion erstellt eine Instanznachricht mit dem Ergebnis, die an die übergeordnete Orchestratorinstanz adressiert ist.
  • Eine abgeschlossene Orchestratorfunktion aktualisiert den Orchesterstatus und den Verlauf und kann neue Nachrichten erstellen.
  • Eine abgeschlossene Entitätsfunktion aktualisiert den Entitätsstatus und kann auch neue Instanznachrichten erstellen.

Bei Orchestrierungen stellt jedes Arbeitselement eine Episode der Ausführung dieser Orchestrierung dar. Eine Episode beginnt, wenn es neue Nachrichten für den Orchestrator gibt, die verarbeitet werden müssen. Eine solche Nachricht kann angeben, dass die Orchestrierung gestartet werden soll, oder dass eine Aktivität, ein Entitätsaufruf, ein Timer oder eine Unterorchestrierung abgeschlossen wurde, oder sie kann ein externes Ereignis darstellen. Die Nachricht löst ein Arbeitselement aus, das es dem Orchestrator ermöglicht, das Ergebnis zu verarbeiten und mit der nächsten Episode fortzufahren. Diese Episode endet, wenn der Orchestrator entweder abgeschlossen wurde oder einen Punkt erreicht, an dem er auf neue Nachrichten warten muss.

Ausführungsbeispiel

Betrachten Sie eine Fan-Out-Fan-In-Orchestrierung, bei der zwei Aktivitäten parallel gestartet werden und gewartet wird, bis beide abgeschlossen wurden:

[FunctionName("Example")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Task t1 = context.CallActivityAsync<int>("MyActivity", 1);
    Task t2 = context.CallActivityAsync<int>("MyActivity", 2);
    await Task.WhenAll(t1, t2);
}

Nachdem diese Orchesterung von einem Client initiiert wurde, wird sie von der Funktions-App als Sequenz von Arbeitselementen verarbeitet. Jedes abgeschlossene Arbeitselement aktualisiert beim Committen den Status des Aufgabenhubs. Hier sind die Schritte aufgeführt:

  1. Ein Client fordert an, eine neue Orchestrierung mit der Instanz-ID „123“ zu starten. Nachdem der Client diese Anforderung abgeschlossen hat, enthält der Aufgabenhub einen Platzhalter für den Orchesterstatus und eine Instanznachricht:

    workitems-illustration-step-1

    Die Bezeichnung ExecutionStarted ist eine der vielen Verlaufsereignistypen, die die verschiedenen Arten von Nachrichten und Ereignissen identifizieren, die am Verlauf einer Orchestrierung teilnehmen.

  2. Ein Worker führt ein Orchestratorarbeitselement aus, um die ExecutionStarted-Nachricht zu verarbeiten. Er ruft die Orchestratorfunktion auf, die mit der Ausführung des Orchestrierungscodes beginnt. Dieser Code plant zwei Aktivitäten und beendet dann die Ausführung, wenn er auf die Ergebnisse wartet. Nachdem der Worker dieses Arbeitselement committet hat, enthält der Aufgabenhub Folgendes:

    workitems-illustration-step-2

    Der Runtimestatus ist jetzt Running, zwei neue TaskScheduled-Nachrichten wurden hinzugefügt, und der Verlauf enthält nun die fünf Ereignisse OrchestratorStarted, ExecutionStarted, TaskScheduled, TaskScheduled und OrchestratorCompleted. Diese Ereignisse stellen die erste Episode der Ausführung dieser Orchestrierung dar.

  3. Ein Worker führt ein Aktivitätsarbeitselement aus, um eine der TaskScheduled-Nachrichten zu verarbeiten. Er ruft die Aktivitätsfunktion mit der Eingabe „2“ auf. Wenn die Aktivitätsfunktion abgeschlossen ist, wird eine TaskCompleted-Nachricht mit dem Ergebnis erstellt. Nachdem der Worker dieses Arbeitselement committet hat, enthält der Aufgabenhub Folgendes:

    workitems-illustration-step-3

  4. Ein Worker führt ein Orchestratorarbeitselement aus, um die TaskCompleted-Nachricht zu verarbeiten. Wenn die Orchestrierung noch im Arbeitsspeicher zwischengespeichert ist, kann die Ausführung einfach fortgesetzt werden. Andernfalls gibt der Worker zuerst den Verlauf wieder, um den aktuellen Zustand der Orchestrierung wiederherzustellen. Anschließend wird die Orchestrierung fortgesetzt und das Ergebnis der Aktivität übermittelt. Nach dem Empfang dieses Ergebnisses wartet die Orchestrierung weiterhin auf das Ergebnis der anderen Aktivität, sodass die Ausführung erneut beendet wird. Nachdem der Worker dieses Arbeitselement committet hat, enthält der Aufgabenhub Folgendes:

    workitems-illustration-step-4

    Der Orchestrierungsverlauf enthält jetzt drei weitere Ereignisse OrchestratorStarted, TaskCompleted und OrchestratorCompleted. Diese Ereignisse stellen die zweite Episode der Ausführung dieser Orchestrierung dar.

  5. Ein Worker führt ein Aktivitätsarbeitselement aus, um die verbleibende TaskScheduled-Nachricht zu verarbeiten. Er ruft die Aktivitätsfunktion mit der Eingabe „1“ auf. Nachdem der Worker dieses Arbeitselement committet hat, enthält der Aufgabenhub Folgendes:

    workitems-illustration-step-5

  6. Ein Worker führt ein weiteres Orchestratorarbeitselement aus, um die TaskCompleted-Nachricht zu verarbeiten. Nach dem Empfang dieses zweiten Ergebnisses wird die Orchestrierung abgeschlossen. Nachdem der Worker dieses Arbeitselement committet hat, enthält der Aufgabenhub Folgendes:

    workitems-illustration-step-6

    Der Runtimestatus ist jetzt Completed, und der Orchestrierungsverlauf enthält nun vier weitere Ereignisse OrchestratorStarted, TaskCompleted, ExecutionCompleted und OrchestratorCompleted. Diese Ereignisse stellen die dritte und letzte Episode der Ausführung dieser Orchestrierung dar.

Der endgültige Verlauf für die Ausführung dieser Orchestrierung enthält dann die 12 Ereignisse OrchestratorStarted, ExecutionStarted, TaskScheduled, TaskScheduled, OrchestratorCompleted, OrchestratorStarted, TaskCompleted, OrchestratorCompleted, OrchestratorStarted, TaskCompleted, ExecutionCompleted und OrchestratorCompleted.

Hinweis

Der gezeigte Zeitplan ist nicht der einzige: Es gibt viele leicht verschiedene mögliche Zeitplane. Wenn beispielsweise die zweite Aktivität früher abgeschlossen wird, können beide TaskCompleted-Instanznachrichten von einem einzelnen Arbeitselement verarbeitet werden. In diesem Fall ist der Ausführungsverlauf etwas kürzer, da es nur zwei Episoden gibt, und er enthält die folgenden 10 Ereignisse: OrchestratorStarted, ExecutionStarted, TaskScheduled, TaskScheduled, OrchestratorCompleted, OrchestratorStarted, TaskCompleted, TaskCompleted, ExecutionCompleted und OrchestratorCompleted.

Aufgabenhubverwaltung

Im nächsten Schritt sehen wir uns genauer an, wie Aufgabenhubs erstellt oder gelöscht werden, wie Aufgabenhubs richtig verwendet werden, wenn mehrere Funktions-Apps ausgeführt werden, und wie der Inhalt von Aufgabenhubs untersucht werden kann.

Erstellen und Löschen

Ein leerer Aufgabenhub mit allen erforderlichen Ressourcen wird automatisch im Speicher erstellt, wenn eine Funktions-App zum ersten Mal gestartet wird.

Wenn Sie den standardmäßigen Azure Storage-Anbieter verwenden, ist keine zusätzliche Konfiguration erforderlich. Andernfalls folgen Sie den Anweisungen zum Konfigurieren von Speicheranbietern, um sicherzustellen, dass der Speicheranbieter die für den Aufgabenhub erforderlichen Speicherressourcen ordnungsgemäß bereitstellen und darauf zugreifen kann.

Hinweis

Der Aufgabenhub wird nicht automatisch gelöscht, wenn Sie die Funktions-App beenden oder löschen. Sie müssen den Aufgabenhub, dessen Inhalt oder das enthaltende Speicherkonto manuell löschen, wenn Sie diese Daten nicht mehr beibehalten möchten.

Tipp

In einem Entwicklungsszenario müssen Sie möglicherweise häufig aus einem sauberen Zustand neu starten. Um dies schnell zu erledigen, können Sie einfach den Namen des konfigurierten Aufgabenhubs ändern. Dadurch wird die Erstellung eines neuen, leeren Aufgabenhubs erzwungen, wenn Sie die Anwendung neu starten. Beachten Sie, dass die alten Daten in diesem Fall nicht gelöscht werden.

Mehrere Funktions-Apps

Wenn sich mehrere Funktions-Apps ein Speicherkonto teilen, muss jede Funktions-App mit einem separaten Aufgabenhubnamen konfiguriert werden. Diese Anforderung gilt auch für Stagingslots: Jeder Stagingslot muss mit einem eindeutigen Aufgabenhubnamen konfiguriert werden. Ein einzelnes Speicherkonto kann mehrere Aufgabenhubs enthalten. Diese Einschränkung gilt im Allgemeinen auch für andere Speicheranbieter.

Die folgende Abbildung veranschaulicht einen Aufgabenhub pro Funktions-App in freigegebenen und dedizierten Azure Storage-Konten.

Diagram showing shared and dedicated storage accounts.

Hinweis

Eine Ausnahme von der Aufgabenhub-Freigaberegel besteht, wenn Sie Ihre Anwendung für eine regionale Notfallwiederherstellung konfigurieren. Weitere Informationen finden Sie im Artikel Notfallwiederherstellung und Geoverteilung.

Inhaltsuntersuchung

Es gibt mehrere häufig verwendete Möglichkeiten zum Überprüfen des Inhalts eines Aufgabenhubs:

  1. Innerhalb einer Funktions-App bietet das Clientobjekt Methoden zum Abfragen des Instanzspeichers. Weitere Informationen dazu, welche Arten von Abfragen unterstützt werden, finden Sie im Artikel zur Instanzverwaltung.
  2. Ebenso bietet die HTTP-API REST-Anforderungen, um den Zustand der Orchestrierungen und Entitäten abzufragen. Weitere Einzelheiten finden Sie in der HTTP-API-Referenz.
  3. Das Durable Functions Monitor-Tool kann Aufgabenhubs überprüfen und bietet verschiedene Optionen für die visuelle Anzeige.

Für einige Speicheranbieter ist es auch möglich, den Aufgabenhub zu überprüfen, indem Sie direkt zum zugrunde liegenden Speicher wechseln:

  • Wenn Sie den Azure Storage-Anbieter verwenden, werden die Instanzzustände in der Instanztabelle und der Verlaufstabelle gespeichert, die mithilfe von Tools wie Azure Storage-Explorer überprüft werden können.
  • Wenn Sie den MSSQL-Speicheranbieter verwenden, können SQL-Abfragen und -Tools verwendet werden, um den Inhalt des Aufgabenhubs innerhalb der Datenbank zu überprüfen.

Darstellung im Speicher

Jeder Speicheranbieter verwendet eine andere interne Organisation, um Aufgabenhubs im Speicher darzustellen. Das Verständnis dieser Organisation ist zwar nicht erforderlich, kann aber bei der Problembehandlung einer Funktions-App oder bei dem Versuch, Leistungs-, Skalierbarkeits- oder Kostenziele sicherzustellen, hilfreich sein. Wir erläutern daher kurz für jeden Speicheranbieter, wie die Daten im Speicher organisiert sind. Weitere Informationen zu den verschiedenen Speicheranbieteroptionen und deren Vergleich finden Sie unter Durable Functions-Speicheranbieter.

Azure Storage-Anbieter

Der Azure Storage-Anbieter stellt den Aufgabenhub im Speicher mithilfe der folgenden Komponenten dar:

  • Zwei Azure-Tabellen speichern die Instanzzustände.
  • Eine Azure-Warteschlange speichert die Aktivitätsnachrichten.
  • Mindestens eine Azure-Warteschlange speichert die Instanznachrichten. Jede dieser sogenannten Steuerungswarteschlangen stellt eine Partition dar, der basierend auf dem Hash der Instanz-ID eine Teilmenge aller Instanznachrichten zugeordnet wird.
  • Einige zusätzliche Blob-Container, die für Leaseblobs und/oder große Nachrichten verwendet werden.

Beispielsweise enthält ein Aufgabenhub mit dem Namen xyz mit PartitionCount = 4 die folgenden Warteschlangen und Tabellen:

Diagram showing Azure Storage provider storage storage organization for 4 control queues.

Im Folgenden werden diese Komponenten und ihre Rolle genauer beschrieben.

Weitere Informationen dazu, wie Aufgabenhubs vom Azure Storage-Anbieter dargestellt werden, finden Sie in der Dokumentation zum Azure Storage-Anbieter.

Netherite-Speicheranbieter

Netherite partitioniert alle Aufgabenhubzustände in eine angegebene Anzahl von Partitionen. Im Speicher werden die folgenden Ressourcen verwendet:

  • Ein Azure Storage-Blobcontainer, der alle Blobs enthält, gruppiert nach Partition.
  • Eine Azure-Tabelle, die veröffentlichte Metriken zu den Partitionen enthält.
  • Ein Azure Event Hubs-Namespace zum Übermitteln von Nachrichten zwischen Partitionen.

Beispielsweise wird ein Aufgabenhub mit dem Namen mytaskhub mit PartitionCount = 32 im Speicher wie folgt dargestellt:

Diagram showing Netherite storage organization for 32 partitions.

Hinweis

Der gesamte Vorgangshubzustand wird im x-storage-Blobcontainer gespeichert. Die DurableTaskPartitions-Tabelle und der EventHubs-Namespace enthalten redundante Daten: Wenn ihre Inhalte verloren gehen, können sie automatisch wiederhergestellt werden. Daher ist es nicht erforderlich, den Azure Event Hubs Namespace so zu konfigurieren, dass Nachrichten über die Standardablaufzeit hinaus aufbewahrt werden.

Netherite verwendet einen Ereignisquellenmechanismus basierend auf einem Protokoll und Prüfpunkten, um den aktuellen Zustand einer Partition darzustellen. Sowohl Blockblobs als auch Seitenblobs werden verwendet. Es ist nicht möglich, dieses Format direkt aus dem Speicher zu lesen, sodass die Funktions-App beim Abfragen des Instanzspeichers ausgeführt werden muss.

Weitere Informationen zu Aufgabenhubs für den Netherite-Speicheranbieter finden Sie unter Aufgabenhubinformationen für den Netherite-Speicheranbieter.

MSSQL-Speicheranbieter

Alle Aufgabenhubdaten werden in einer einzelnen relationalen Datenbank gespeichert, wobei mehrere Tabellen verwendet werden:

  • Die dt.Instances- und dt.History-Tabellen speichern die Instanzzustände.
  • Die dt.NewEvents-Tabelle speichert die Instanznachrichten.
  • Die dt.NewTasks-Tabelle speichert die Aktivitätsnachrichten.

Diagram showing MSSQL storage organization.

Damit mehrere Aufgabenhubs unabhängig voneinander in derselben Datenbank vorhanden können, enthält jede Tabelle eine TaskHub-Spalte als Teil ihres Primärschlüssels. Im Gegensatz zu den anderen beiden Anbietern verfügt der MSSQL-Anbieter nicht über ein Konzept von Partitionen.

Weitere Informationen zu Aufgabenhubs für den MSSQL-Speicheranbieter finden Sie unter Aufgabenhubinformationen für den SQL-Speicheranbieter (MSSQL-Speicheranbieter).

Aufgabenhubnamen

Aufgabenhubs werden anhand eines Namens identifiziert, der den folgenden Regeln genügen muss:

  • Enthält ausschließlich alphanumerische Zeichen.
  • Beginnen mit einem Buchstaben.
  • Ist mindestens 3 Zeichen und höchstens 45 Zeichen lang.

Der Name des Aufgabenhubs wird in der Datei host.json deklariert, wie im folgenden Beispiel gezeigt:

host.json (Functions 2.0)

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "MyTaskHub"
    }
  }
}

host.json (Functions 1.x)

{
  "durableTask": {
    "hubName": "MyTaskHub"
  }
}

Aufgabenhubs können auch mithilfe von App-Einstellungen konfiguriert werden, wie in der folgenden Beispieldatei host.json gezeigt:

host.json (Functions 1.0)

{
  "durableTask": {
    "hubName": "%MyTaskHub%"
  }
}

host.json (Functions 2.0)

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "%MyTaskHub%"
    }
  }
}

Der Name des Aufgabenhubs wird auf den Wert der App-Einstellung MyTaskHub festgelegt. Die folgende Datei local.settings.json veranschaulicht, wie die Einstellungen für MyTaskHub als samplehubname definiert werden:

{
  "IsEncrypted": false,
  "Values": {
    "MyTaskHub" : "samplehubname"
  }
}

Hinweis

Bei Verwendung von Bereitstellungsslots empfiehlt es sich, den Aufgabenhubnamen mithilfe von App-Einstellungen zu konfigurieren. Wenn von einem bestimmten Slot immer ein bestimmter Aufgabenhub verwendet werden soll, verwenden Sie slotpersistente App-Einstellungen.

Namen von Aufgabenhubs können nicht nur in host.json, sondern auch in Metadaten der Orchestrierungsclientbindung konfiguriert werden. Dies ist nützlich, wenn Sie auf Orchestrierungen oder Entitäten zugreifen müssen, die sich in einer separaten Funktions-App befinden. Der folgende Code veranschaulicht das Schreiben einer Funktion, die eine Orchestrierungsclientbindung verwendet, um mit einem als App-Einstellung konfigurierten Aufgabenhub zusammenzuarbeiten:

[FunctionName("HttpStart")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
    [DurableClient(TaskHub = "%MyTaskHub%")] IDurableOrchestrationClient starter,
    string functionName,
    ILogger log)
{
    // Function input comes from the request content.
    object eventData = await req.Content.ReadAsAsync<object>();
    string instanceId = await starter.StartNewAsync(functionName, eventData);

    log.LogInformation($"Started orchestration with ID = '{instanceId}'.");

    return starter.CreateCheckStatusResponse(req, instanceId);
}

Hinweis

Das vorherige Beispiel gilt für Durable Functions 2.x. Für Durable Functions 1.x müssen Sie DurableOrchestrationContext anstelle von IDurableOrchestrationContext verwenden. Weitere Informationen zu den Unterschieden zwischen den Versionen finden Sie im Artikel Durable Functions-Versionen.

Hinweis

Das Konfigurieren von Aufgabenhubnamen in Clientbindungsmetadaten ist nur erforderlich, wenn Sie eine Funktions-App verwenden, um auf Orchestrierungen und Entitäten in einer anderen Funktions-App zuzugreifen. Wenn die Clientfunktionen in derselben Funktions-App wie die Orchestrierungen und Entitäten definiert sind, sollten Sie die Angabe von Aufgabenhubnamen in den Bindungsmetadaten vermeiden. Standardmäßig erhalten alle Clientbindungen ihre Taskhubmetadaten aus den Einstellungen in host.json.

Aufgabenhubnamen müssen mit einem Buchstaben beginnen und bestehen nur aus Buchstaben und Ziffern. Wenn kein Name angegeben ist, wird ein Aufgabenhub-Standardname verwendet, wie in der folgenden Tabelle gezeigt:

Version der Durable-Erweiterung Aufgabenhub-Standardname
2.x Bei der Bereitstellung in Azure wird der Aufgabenhubname vom Namen der Funktions-App abgeleitet. Bei der Ausführung außerhalb von Azure lautet der Standardname des Aufgabenhubs TestHubName.
1.x Der Standardname des Aufgabenhubs für alle Umgebungen lautet DurableFunctionsHub.

Weitere Informationen zu den Unterschieden zwischen den Erweiterungsversionen finden Sie im Artikel Durable Functions-Versionen.

Hinweis

Die einzelnen Aufgabenhubs werden über den Namen unterschieden, wenn in einem freigegebenen Speicherkonto mehrere Aufgabenhubs vorhanden sind. Wenn sich mehrere Funktions-Apps ein freigegebenes Speicherkonto teilen, müssen Sie für die einzelnen Aufgabenhubs in der Datei host.json explizit unterschiedliche Namen konfigurieren. Andernfalls konkurrieren die verschiedenen Funktions-Apps miteinander um Nachrichten, was zu undefiniertem Verhalten führen kann, einschließlich Orchestrierungen, die unerwartet im Zustand Pending oder Running „stecken bleiben“.

Nächste Schritte