Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Das Monitormuster ist ein wiederkehrender Prozess in einem Workflow, der ein externes System abfragt, bis eine Bedingung erfüllt ist. Zum Beispiel überprüft er den Jobstatus, bis er abgeschlossen ist, oder beobachtet Wetterdaten, bis der Himmel klar ist. Im Gegensatz zu einem Timertrigger mit fester Zeitplanung wartet ein Monitor zwischen Iterationen (Vermeiden von Überlappungen), unterstützt dynamische Intervalle und kann sich selbst beenden, sobald die Bedingung erfüllt ist oder ein Timeout abläuft.
Dieser Artikel erklärt, wie man das Monitor-Muster mithilfe von robusten Orchestrierungen implementiert.
Tip
In diesem Artikel wird die vollständige Implementierung gezeigt. Für einen konzeptionellen Überblick über Anwendungsfälle für dauerhafte Orchestrierung siehe Was ist eine dauerhafte Aufgabe?
Important
Die Unterstützung für das In-Process-Modell endet am 10. November 2026. Es wird dringend empfohlen, dass Sie Ihre Apps in das isolierte Workermodell migrieren, um vollständigen Support zu erhalten.
Die Durable Functions Beispiele umfassen ein Wetterüberwachungsszenario (C#/JavaScript) und ein GitHub Problemüberwachungsszenario (Python).
Hinweis
Version 4 des Node.js Programmiermodells für Azure Functions ist allgemein verfügbar. Das v4-Modell wurde entwickelt, um eine flexiblere und intuitivere Oberfläche für JavaScript- und TypeScript-Entwickler bereitzustellen. Weitere Informationen zu den Unterschieden zwischen v3 und v4 finden Sie im Migrationshandbuch.
In den folgenden Codeausschnitten bezeichnet JavaScript (PM4) das Programmiermodell v4, die neue Oberfläche.
Das Beispiel der Durable Task SDKs demonstriert die Überwachung des Jobstatus mit konfigurierbaren Abfrageintervallen mittels .NET, JavaScript, Python und Java.
Voraussetzungen
- Schließen Sie den Schnellstartartikel ab.
- Klone oder lade das Sample-Projekt von GitHub herunter
- .NET 8.0 SDK oder höher
- Zugriff auf Azure Durable Task Scheduler oder den lokalen Emulator
Übersicht über das Überwachungsszenario
Dieses Beispiel überwacht die aktuellen Wetterbedingungen an einem bestimmten Ort und benachrichtigt einen Benutzer per SMS, wenn das Wetter schön ist. Sie könnten eine reguläre, per Timer ausgelöste Funktion verwenden, um das Wetter zu beobachten und Benachrichtigungen zu senden. Ein Problem mit diesem Ansatz ist jedoch das Lebenslange Management. Wenn nur eine einzige Benachrichtigung gesendet werden soll, muss der Monitor sich selbst deaktivieren, nachdem schönes Wetter erkannt wurde.
Das Überwachungsmuster bietet neben weiteren Vorteilen den Vorzug, dass es die eigene Ausführung beenden kann:
- Monitore werden in Intervallen und nicht nach Zeitplänen ausgeführt: Ein Timer-Trigger wird jede Stunde ausgeführt, ein Monitor wartet eine Stunde zwischen den Vorgängen. Die Aktionen eines Monitors überschneiden sich nicht, es sei denn, Sie geben etwas anderes an, was bei langlaufenden Aufgaben wichtig sein kann.
- Monitore können dynamische Intervalle haben: Die Wartezeit kann sich aufgrund einer Bedingung ändern.
- Monitore können beendet werden, wenn eine bestimmte Bedingung erfüllt ist. Sie können auch von einem anderen Prozess beendet werden.
- Für Monitore können Parameter angegeben werden. Das Beispiel zeigt, wie derselbe Überwachungsprozess auf jeden angeforderten Standort, jede Telefonnummer oder jedes Repository angewendet werden kann.
- Monitore sind skalierbar. Da jeder Monitor eine Orchestrierungsinstanz ist, kann man mehrere Monitore erstellen, ohne neue Funktionen erstellen oder mehr Code definieren zu müssen.
- Monitore lassen sich problemlos in größere Workflows integrieren. Ein Monitor kann ein Abschnitt einer komplexeren Orchestrierungsfunktion oder eine Unter-Orchestrierung sein.
In diesem Beispiel wird der Status eines lang andauernden Auftrags überwacht, und das Endergebnis wird zurückgegeben, wenn der Auftrag abgeschlossen oder eine Zeitüberschreitung auftritt. Sie können eine reguläre Abfrageschleife verwenden, um den Auftragsstatus zu überprüfen, aber dieser Ansatz ist mit Einschränkungen hinsichtlich der Lebenszyklusverwaltung und Zuverlässigkeit verbunden.
Das Überwachungsmuster bietet folgende Vorteile:
- Dauerhafte Abfrage: Die Orchestrierung übersteht Prozessneustarts und kann die Überwachung auch nach Ausfällen fortsetzen.
- Konfigurierbare Intervalle: Sie können die Wartezeit zwischen den Statusprüfungen dynamisch anpassen.
- Timeout-Unterstützung: Der Monitor kann beendet werden, wenn eine Bedingung erfüllt ist oder ein Timeout abläuft.
- Statussichtbarkeit: Clients können den benutzerdefinierten Status der Orchestrierung abfragen, um den aktuellen Fortschritt der Überwachung zu sehen.
- Skalierbarkeit: Mehrere Monitore können gleichzeitig ausgeführt werden, wobei jeder unterschiedliche Aufgaben überwacht.
Konfiguration
Konfigurieren der Twilio-Integration
Dieses Beispiel beinhaltet die Verwendung des Twilio-Diensts zum Senden von SMS-Nachrichten an ein Mobiltelefon. Azure Functions bietet bereits Unterstützung für Twilio über die Twilio binding und das Beispiel verwendet dieses Feature.
Zunächst benötigen Sie ein Twilio-Konto. Unter https://www.twilio.com/try-twilio können Sie kostenlos eines erstellen. Fügen Sie nach der Einrichtung Ihres Kontos die folgenden drei App-Einstellungen zu Ihrer Funktions-App hinzu.
| Name der App-Einstellung | Wertbeschreibung |
|---|---|
| TwilioAccountSid | Die SID für Ihr Twilio-Konto |
| TwilioAuthToken | Das Authentifizierungstoken für Ihr Twilio-Konto |
| TwilioPhoneNumber | Die Ihrem Twilio-Konto zugeordnete Telefonnummer. Diese wird für das Senden von SMS-Nachrichten verwendet. |
Konfigurieren einer Wetter-API
In den C#/JavaScript-Beispielen wird eine Wetter-API aufgerufen, um aktuelle Bedingungen zu überprüfen. Sie müssen Ihren eigenen Wetter-API-Schlüssel angeben und den Beispielcode entsprechend aktualisieren. Der Beispielcode bezieht sich auf eine WeatherUndergroundApiKey App-Einstellung – ersetze diesen Schlüssel durch den Schlüssel deines gewählten Wetteranbieters.
| Name der App-Einstellung | Wertbeschreibung |
|---|---|
| WeatherUnderground-API-Schlüssel | Ihr Wetter-API-Schlüssel (ersetzen Sie nach Bedarf durch den Schlüsselnamen Ihres Anbieters). |
Orchestrator
Isoliertes Modell
using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask;
using Microsoft.Extensions.Logging;
namespace VSSample;
public static partial class Monitor
{
[Function("E3_Monitor")]
public static async Task Run(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
MonitorRequest input = context.GetInput<MonitorRequest>()
?? throw new ArgumentNullException(nameof(context), "An input object is required.");
VerifyRequest(input);
ILogger logger = context.CreateReplaySafeLogger("E3_Monitor");
DateTime endTime = context.CurrentUtcDateTime.AddHours(6);
logger.LogInformation(
"Instantiating monitor for {Location}. Expires: {EndTime}.",
input.Location,
endTime);
while (context.CurrentUtcDateTime < endTime)
{
logger.LogInformation(
"Checking current weather conditions for {Location} at {CurrentTime}.",
input.Location,
context.CurrentUtcDateTime);
bool isClear = await context.CallActivityAsync<bool>(
"E3_GetIsClear",
input.Location);
if (isClear)
{
await context.CallActivityAsync(
"E3_SendGoodWeatherAlert",
input.Phone);
break;
}
DateTime nextCheckpoint = context.CurrentUtcDateTime.AddMinutes(30);
await context.CreateTimer(nextCheckpoint, CancellationToken.None);
}
logger.LogInformation("Monitor expiring.");
}
private static void VerifyRequest(MonitorRequest request)
{
ArgumentNullException.ThrowIfNull(request.Location);
ArgumentException.ThrowIfNullOrEmpty(request.Phone);
}
}
public sealed class MonitorRequest
{
public required Location Location { get; init; }
public required string Phone { get; init; }
}
public sealed class Location
{
public required string State { get; init; }
public required string City { get; init; }
public override string ToString() => $"{City}, {State}";
}
In-Prozess-Modell
[FunctionName("E3_Monitor")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext monitorContext, ILogger log)
{
MonitorRequest input = monitorContext.GetInput<MonitorRequest>();
if (!monitorContext.IsReplaying) { log.LogInformation($"Received monitor request. Location: {input?.Location}. Phone: {input?.Phone}."); }
VerifyRequest(input);
DateTime endTime = monitorContext.CurrentUtcDateTime.AddHours(6);
if (!monitorContext.IsReplaying) { log.LogInformation($"Instantiating monitor for {input.Location}. Expires: {endTime}."); }
while (monitorContext.CurrentUtcDateTime < endTime)
{
// Check the weather
if (!monitorContext.IsReplaying) { log.LogInformation($"Checking current weather conditions for {input.Location} at {monitorContext.CurrentUtcDateTime}."); }
bool isClear = await monitorContext.CallActivityAsync<bool>("E3_GetIsClear", input.Location);
if (isClear)
{
// It's not raining! Or snowing. Or misting. Tell our user to take advantage of it.
if (!monitorContext.IsReplaying) { log.LogInformation($"Detected clear weather for {input.Location}. Notifying {input.Phone}."); }
await monitorContext.CallActivityAsync("E3_SendGoodWeatherAlert", input.Phone);
break;
}
else
{
// Wait for the next checkpoint
var nextCheckpoint = monitorContext.CurrentUtcDateTime.AddMinutes(30);
if (!monitorContext.IsReplaying) { log.LogInformation($"Next check for {input.Location} at {nextCheckpoint}."); }
await monitorContext.CreateTimer(nextCheckpoint, CancellationToken.None);
}
}
log.LogInformation($"Monitor expiring.");
}
[Deterministic]
private static void VerifyRequest(MonitorRequest request)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request), "An input object is required.");
}
if (request.Location == null)
{
throw new ArgumentNullException(nameof(request.Location), "A location input is required.");
}
if (string.IsNullOrEmpty(request.Phone))
{
throw new ArgumentNullException(nameof(request.Phone), "A phone number input is required.");
}
}
Die Orchestratorfunktion erfordert einen Ort zum Überwachen und eine Telefonnummer, an die eine Nachricht gesendet werden kann, wenn das Wetter am Standort klar wird. Du übergibst diese Daten als stark typisiertes MonitorRequest Objekt an die Orchestrator-Funktion.
Diese Orchestratorfunktion führt die folgenden Aktionen aus:
- Ruft den MonitorRequest ab, der aus dem zu überwachenden location und der Telefonnummer besteht, an die eine SMS-Benachrichtigung gesendet wird (oder repo für das Python-Beispiel).
- Es bestimmt den Ablaufzeitpunkt des Monitors. Aus Gründen der Übersichtlichkeit verwendet dieses Beispiel einen hartcodierten Wert.
- Ruft die Statusüberprüfungsaktivität auf, um festzustellen, ob die Bedingung erfüllt ist.
- Wenn die Bedingung erfüllt ist, wird die Alarmaktivität ausgeführt, um eine Benachrichtigung zu senden.
- Erstellt einen dauerhaften Timer, um die Orchestrierung im nächsten Abfrageintervall fortzusetzen. Aus Gründen der Übersichtlichkeit verwendet dieses Beispiel einen hartcodierten Wert.
- Wird fortgesetzt, bis die aktuelle UTC-Zeit die Ablaufzeit des Monitors überschreitet oder eine Warnung gesendet wird.
Man kann mehrere Instanzen der Orchestratorfunktion gleichzeitig ausführen, indem man die Orchestratorfunktion mehrfach aufruft. Du kannst den zu überwachenden Standort und die Telefonnummer angeben, an die du eine Benachrichtigung senden möchtest. Die Orchestrator-Funktion läuft nicht, während du auf den Timer wartest, also wirst du nicht dafür bezahlt.
Der Orchestrator überprüft in regelmäßigen Abständen den Status eines Auftrags und gibt eine Rückmeldung, wenn der Auftrag abgeschlossen ist oder abläuft.
using Microsoft.DurableTask;
using System;
using System.Threading.Tasks;
[DurableTask(nameof(MonitoringJobOrchestration))]
public class MonitoringJobOrchestration : TaskOrchestrator<JobMonitorInput, JobMonitorResult>
{
public override async Task<JobMonitorResult> RunAsync(
TaskOrchestrationContext context, JobMonitorInput input)
{
var jobId = input.JobId;
var pollingInterval = TimeSpan.FromSeconds(input.PollingIntervalSeconds);
var expirationTime = context.CurrentUtcDateTime.AddSeconds(input.TimeoutSeconds);
// Initialize monitoring state
int checkCount = 0;
while (context.CurrentUtcDateTime < expirationTime)
{
// Check current job status
var jobStatus = await context.CallActivityAsync<JobStatus>(
nameof(CheckJobStatusActivity),
new CheckJobInput { JobId = jobId, CheckCount = checkCount });
checkCount = jobStatus.CheckCount;
// Make job status available via custom status
context.SetCustomStatus(jobStatus);
if (jobStatus.Status == "Completed")
{
return new JobMonitorResult
{
JobId = jobId,
FinalStatus = "Completed",
ChecksPerformed = checkCount
};
}
// Calculate next check time
var nextCheck = context.CurrentUtcDateTime.Add(pollingInterval);
if (nextCheck > expirationTime)
{
nextCheck = expirationTime;
}
// Wait until next polling interval
await context.CreateTimer(nextCheck, default);
}
// Timeout reached
return new JobMonitorResult
{
JobId = jobId,
FinalStatus = "Timeout",
ChecksPerformed = checkCount
};
}
}
Dieser Orchestrator führt die folgenden Aktionen aus:
- Verwendet die Auftrags-ID, das Abfrageintervall und das Timeout als Eingabeparameter.
- Zeichnet die Startzeit auf und berechnet die Ablaufzeit.
- Gibt eine Abfrageschleife ein, die den Status des Auftrags überprüft.
- Aktualisiert den benutzerdefinierten Status, damit Kunden den Fortschritt überwachen können.
- Wenn der Auftrag abgeschlossen wird, gibt er das Endergebnis zurück.
- Wenn das Timeout erreicht ist, wird ein Timeout-Status zurückgegeben.
- Verwendet
CreateTimer, um zwischen Abrufversuchen zu warten, ohne Ressourcen zu verbrauchen.
Aktivitäten
Wie bei anderen Beispielen sind die Hilfsaktivitätsfunktionen normale Funktionen, die die activityTrigger Triggerbindung verwenden.
Statusüberprüfungsaktivität
Die E3_GetIsClear-Funktion erfasst die aktuellen Wetterbedingungen mithilfe der Weather Underground API und bestimmt, ob der Himmel klar ist.
Isoliertes Modell
using Microsoft.Azure.Functions.Worker;
namespace VSSample;
public static partial class Monitor
{
[Function("E3_GetIsClear")]
public static async Task<bool> GetIsClear([ActivityTrigger] Location location)
{
WeatherCondition currentConditions =
await WeatherUnderground.GetCurrentConditionsAsync(location);
return currentConditions == WeatherCondition.Clear;
}
}
In-Prozess-Modell
[FunctionName("E3_GetIsClear")]
public static async Task<bool> GetIsClear([ActivityTrigger] Location location)
{
var currentConditions = await WeatherUnderground.GetCurrentConditionsAsync(location);
return currentConditions.Equals(WeatherCondition.Clear);
}
Warnungsaktivität
Die E3_SendGoodWeatherAlert-Funktion verwendet Twilio, um eine SMS zu senden, die den Endnutzer darüber informiert, dass es ein guter Zeitpunkt für einen Spaziergang ist.
Isoliertes Modell
using Microsoft.Azure.Functions.Worker;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
namespace VSSample;
public static partial class Monitor
{
[Function("E3_SendGoodWeatherAlert")]
public static async Task SendGoodWeatherAlert(
[ActivityTrigger] string phoneNumber)
{
string accountSid = Environment.GetEnvironmentVariable("TwilioAccountSid")
?? throw new InvalidOperationException("TwilioAccountSid is not configured.");
string authToken = Environment.GetEnvironmentVariable("TwilioAuthToken")
?? throw new InvalidOperationException("TwilioAuthToken is not configured.");
string fromNumber = Environment.GetEnvironmentVariable("TwilioPhoneNumber")
?? throw new InvalidOperationException("TwilioPhoneNumber is not configured.");
TwilioClient.Init(accountSid, authToken);
await MessageResource.CreateAsync(
to: new PhoneNumber(phoneNumber),
from: new PhoneNumber(fromNumber),
body: "The weather's clear outside! Go take a walk!");
}
}
Hinweis
Um den isolierten Worker-Beispielcode auszuführen, installiere das Twilio NuGet-Paket.
In-Prozess-Modell
[FunctionName("E3_SendGoodWeatherAlert")]
public static void SendGoodWeatherAlert(
[ActivityTrigger] string phoneNumber,
ILogger log,
[TwilioSms(AccountSidSetting = "TwilioAccountSid", AuthTokenSetting = "TwilioAuthToken", From = "%TwilioPhoneNumber%")]
out CreateMessageOptions message)
{
message = new CreateMessageOptions(new PhoneNumber(phoneNumber));
message.Body = $"The weather's clear outside! Go take a walk!";
}
internal class WeatherUnderground
{
private static readonly HttpClient httpClient = new HttpClient();
private static IReadOnlyDictionary<string, WeatherCondition> weatherMapping = new Dictionary<string, WeatherCondition>()
{
{ "Clear", WeatherCondition.Clear },
{ "Overcast", WeatherCondition.Clear },
{ "Cloudy", WeatherCondition.Clear },
{ "Clouds", WeatherCondition.Clear },
{ "Drizzle", WeatherCondition.Precipitation },
{ "Hail", WeatherCondition.Precipitation },
{ "Ice", WeatherCondition.Precipitation },
{ "Mist", WeatherCondition.Precipitation },
{ "Precipitation", WeatherCondition.Precipitation },
{ "Rain", WeatherCondition.Precipitation },
{ "Showers", WeatherCondition.Precipitation },
{ "Snow", WeatherCondition.Precipitation },
{ "Spray", WeatherCondition.Precipitation },
{ "Squall", WeatherCondition.Precipitation },
{ "Thunderstorm", WeatherCondition.Precipitation },
};
internal static async Task<WeatherCondition> GetCurrentConditionsAsync(Location location)
{
var apiKey = Environment.GetEnvironmentVariable("WeatherUndergroundApiKey");
if (string.IsNullOrEmpty(apiKey))
{
throw new InvalidOperationException("The WeatherUndergroundApiKey environment variable was not set.");
}
var callString = string.Format("http://api.wunderground.com/api/{0}/conditions/q/{1}/{2}.json", apiKey, location.State, location.City);
var response = await httpClient.GetAsync(callString);
var conditions = await response.Content.ReadAsAsync<JObject>();
JToken currentObservation;
if (!conditions.TryGetValue("current_observation", out currentObservation))
{
JToken error = conditions.SelectToken("response.error");
if (error != null)
{
throw new InvalidOperationException($"API returned an error: {error}.");
}
else
{
throw new ArgumentException("Could not find weather for this location. Try being more specific.");
}
}
return MapToWeatherCondition((string)(currentObservation as JObject).GetValue("weather"));
}
private static WeatherCondition MapToWeatherCondition(string weather)
{
foreach (var pair in weatherMapping)
{
if (weather.Contains(pair.Key))
{
return pair.Value;
}
}
return WeatherCondition.Other;
}
}
Hinweis
Um den laufenden Beispielcode auszuführen, installieren Sie das Microsoft.Azure.WebJobs.Extensions.Twilio NuGet-Paket.
Die Aktivität überprüft den aktuellen Status des Auftrags. In einer realen Anwendung ruft dieser Schritt eine externe API oder einen externen Dienst auf.
using Microsoft.DurableTask;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
[DurableTask(nameof(CheckJobStatusActivity))]
public class CheckJobStatusActivity : TaskActivity<CheckJobInput, JobStatus>
{
private readonly ILogger<CheckJobStatusActivity> _logger;
public CheckJobStatusActivity(ILogger<CheckJobStatusActivity> logger)
{
_logger = logger;
}
public override Task<JobStatus> RunAsync(TaskActivityContext context, CheckJobInput input)
{
_logger.LogInformation("Checking status for job: {JobId} (check #{CheckCount})",
input.JobId, input.CheckCount + 1);
// Simulate job status - completes after 3 checks
var status = input.CheckCount >= 3 ? "Completed" : "Running";
return Task.FromResult(new JobStatus
{
JobId = input.JobId,
Status = status,
CheckCount = input.CheckCount + 1,
LastCheckTime = DateTime.UtcNow
});
}
}
// Data classes
public class JobMonitorInput
{
public string JobId { get; set; }
public int PollingIntervalSeconds { get; set; } = 5;
public int TimeoutSeconds { get; set; } = 30;
}
public class CheckJobInput
{
public string JobId { get; set; }
public int CheckCount { get; set; }
}
public class JobStatus
{
public string JobId { get; set; }
public string Status { get; set; }
public int CheckCount { get; set; }
public DateTime LastCheckTime { get; set; }
}
public class JobMonitorResult
{
public string JobId { get; set; }
public string FinalStatus { get; set; }
public int ChecksPerformed { get; set; }
}
Führen Sie das Überwachungsbeispiel aus
Indem Sie die im Beispiel enthaltenen HTTP-ausgelösten Funktionen verwenden, können Sie die Orchestrierung starten, indem Sie folgende HTTP-POST-Anfrage senden:
POST https://{host}/orchestrators/E3_Monitor
Content-Length: 77
Content-Type: application/json
{ "location": { "city": "Redmond", "state": "WA" }, "phone": "+1425XXXXXXX" }
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
Location: https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635?taskHub=SampleHubVS&connection=Storage&code={SystemKey}
RetryAfter: 10
{"id": "f6893f25acf64df2ab53a35c09d52635", "statusQueryGetUri": "https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635?taskHub=SampleHubVS&connection=Storage&code={systemKey}", "sendEventPostUri": "https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635/raiseEvent/{eventName}?taskHub=SampleHubVS&connection=Storage&code={systemKey}", "terminatePostUri": "https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635/terminate?reason={text}&taskHub=SampleHubVS&connection=Storage&code={systemKey}"}
Die E3_Monitor Instanz startet und fragt die aktuellen Bedingungen ab. Wenn die Bedingung erfüllt ist, ruft sie eine Aktivitätsfunktion auf, um eine Warnung zu senden; andernfalls wird ein Timer festgelegt. Wenn der Timer abläuft, wird die Orchestrierung fortgesetzt.
Sie können die Orchestrierungsaktivitäten sehen, indem Sie die Funktionsprotokolle im Azure Functions-Portal ansehen.
Die Orchestrierung wird abgeschlossen, sobald das Timeout erreicht ist oder die Bedingung erkannt wird. Sie können die terminate API auch in einer anderen Funktion verwenden oder den terminatePostUri HTTP POST-Webhook aufrufen, auf den in der vorherigen Antwort 202 verwiesen wird. Um den Webhook zu verwenden, ersetzen Sie {text} durch den Grund für die vorzeitige Beendigung. Die HTTP POST-URL sieht ungefähr wie folgt aus:
POST https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635/terminate?reason=Because&taskHub=SampleHubVS&connection=Storage&code={systemKey}
Zum Ausführen des Beispiels benötigen Sie Folgendes:
Starten Sie den Emulator für den dauerhaften Aufgabenplaner (für die lokale Entwicklung):
docker run -d -p 8080:8080 -p 8082:8082 --name dts-emulator mcr.microsoft.com/dts/dts-emulator:latestStarten Sie den Worker , um den Orchestrator und die Aktivitäten zu registrieren.
Führen Sie den Client aus, um eine Überwachungsorchestrierung zu planen.
using System;
using System.Threading.Tasks;
var client = DurableTaskClientBuilder.UseDurableTaskScheduler(connectionString).Build();
// Schedule the monitoring orchestration
var input = new JobMonitorInput
{
JobId = "job-" + Guid.NewGuid().ToString(),
PollingIntervalSeconds = 5,
TimeoutSeconds = 30
};
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(
nameof(MonitoringJobOrchestration), input);
Console.WriteLine($"Started monitoring orchestration: {instanceId}");
// Wait for completion while checking status
while (true)
{
var state = await client.GetInstanceMetadataAsync(instanceId, getInputsAndOutputs: true);
if (state.RuntimeStatus == OrchestrationRuntimeStatus.Completed ||
state.RuntimeStatus == OrchestrationRuntimeStatus.Failed)
{
Console.WriteLine($"Monitoring completed: {state.ReadOutputAs<JobMonitorResult>().FinalStatus}");
break;
}
Console.WriteLine($"Current status: {state.ReadCustomStatusAs<JobStatus>()?.Status}");
await Task.Delay(2000);
}
Nächste Schritte
Dieses Beispiel zeigt, wie man Durable Functions nutzt, um den Status einer externen Quelle mithilfe von Durable Timern und bedingter Logik zu überwachen. Im nächsten Beispiel wird gezeigt, wie externe Ereignisse und dauerhafte Zeitgeber verwendet werden, um menschliche Interaktionen zu behandeln.
In diesem Beispiel wurde gezeigt, wie Sie die SdKs für dauerhafte Aufgaben verwenden, um das Überwachungsmuster mit dauerhaften Zeitgebern und Statusverfolgung zu implementieren. Um mehr über andere Muster und Merkmale zu erfahren, siehe: