Status der benutzerdefinierten Orchestrierung in Durable Functions (Azure Functions)
Artikel
Mit dem benutzerdefinierten Orchestrierungsstatus können Sie einen benutzerdefinierten Statuswert für Ihre Orchestratorfunktion festlegen. Dieser Status wird über die HTTP GetStatus-API oder die entsprechende SDK-API im Orchestrierungsclientobjekt bereitgestellt.
Beispiele für Anwendungsfälle
Visualisieren des Fortschritts
Clients können den Statusendpunkt per Poll abrufen und eine Statusanzeige zur Visualisierung der aktuellen Ausführungsphase anzeigen. Das folgende Beispiel veranschaulicht die Ausführungsfreigabe:
Diese C#-Beispiele wurden für Durable Functions 2.x geschrieben und sind nicht mit Durable Functions 1.x kompatibel. Weitere Informationen zu den Unterschieden zwischen den Versionen finden Sie im Artikel Durable Functions-Versionen.
Ein weiteres interessantes Szenario ist die Segmentierung der Benutzer durch Zurückgeben einer angepassten Ausgabe basierend auf bestimmten Eigenschaften oder Interaktionen. Mithilfe des Status der benutzerdefinierten Orchestrierung bleibt der clientseitige Code generisch. Alle wichtigen Änderungen erfolgen auf der Serverseite, wie im folgenden Beispiel gezeigt:
[FunctionName("CityRecommender")]
public static void Run(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
int userChoice = context.GetInput<int>();
switch (userChoice)
{
case 1:
context.SetCustomStatus(new
{
recommendedCities = new[] {"Tokyo", "Seattle"},
recommendedSeasons = new[] {"Spring", "Summer"}
});
break;
case 2:
context.SetCustomStatus(new
{
recommendedCities = new[] {"Seattle, London"},
recommendedSeasons = new[] {"Summer"}
});
break;
case 3:
context.SetCustomStatus(new
{
recommendedCities = new[] {"Tokyo, London"},
recommendedSeasons = new[] {"Spring", "Summer"}
});
break;
}
// Wait for user selection and refine the recommendation
}
CityRecommender-Orchestrator
const df = require("durable-functions");
module.exports = df.orchestrator(function*(context) {
const userChoice = context.df.getInput();
switch (userChoice) {
case 1:
context.df.setCustomStatus({
recommendedCities: [ "Tokyo", "Seattle" ],
recommendedSeasons: [ "Spring", "Summer" ],
});
break;
case 2:
context.df.setCustomStatus({
recommendedCities: [ "Seattle", "London" ],
recommendedSeasons: [ "Summer" ],
});
break;
case 3:
context.df.setCustomStatus({
recommendedCity: [ "Tokyo", "London" ],
recommendedSeasons: [ "Spring", "Summer" ],
});
break;
}
// Wait for user selection and refine the recommendation
});
CityRecommender-Orchestrator
import azure.functions as func
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
userChoice = int(context.get_input())
if userChoice == 1:
context.set_custom_status({
'recommendedCities' : ['Tokyo', 'Seattle'],
'recommendedSeasons' : ['Spring', 'Summer']
}))
if userChoice == 2:
context.set_custom_status({
'recommendedCities' : ['Seattle', 'London']
'recommendedSeasons' : ['Summer']
}))
if userChoice == 3:
context.set_custom_status({
'recommendedCities' : ['Tokyo', 'London'],
'recommendedSeasons' : ['Spring', 'Summer']
}))
# Wait for user selection and refine the recommendation
main = df.Orchestrator.create(orchestrator_function)
CityRecommender-Orchestrator
param($Context)
$userChoice = $Context.Input -as [int]
if ($userChoice -eq 1) {
Set-DurableCustomStatus -CustomStatus @{ recommendedCities = @('Tokyo', 'Seattle');
recommendedSeasons = @('Spring', 'Summer')
}
}
if ($userChoice -eq 2) {
Set-DurableCustomStatus -CustomStatus @{ recommendedCities = @('Seattle', 'London');
recommendedSeasons = @('Summer')
}
}
if ($userChoice -eq 3) {
Set-DurableCustomStatus -CustomStatus @{ recommendedCities = @('Tokyo', 'London');
recommendedSeasons = @('Spring', 'Summer')
}
}
# Wait for user selection and refine the recommendation
@FunctionName("CityRecommender")
public void cityRecommender(
@DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
int userChoice = ctx.getInput(int.class);
switch (userChoice) {
case 1:
ctx.setCustomStatus(new Recommendation(
new String[]{ "Tokyo", "Seattle" },
new String[]{ "Spring", "Summer" }));
break;
case 2:
ctx.setCustomStatus(new Recommendation(
new String[]{ "Seattle", "London" },
new String[]{ "Summer" }));
break;
case 3:
ctx.setCustomStatus(new Recommendation(
new String[]{ "Tokyo", "London" },
new String[]{ "Spring", "Summer" }));
break;
}
// Wait for user selection with an external event
}
class Recommendation {
public Recommendation() { }
public Recommendation(String[] cities, String[] seasons) {
this.recommendedCities = cities;
this.recommendedSeasons = seasons;
}
public String[] recommendedCities;
public String[] recommendedSeasons;
}
Anweisungsspezifikation
Der Orchestrator kann den Clients eindeutige Anweisungen über den benutzerdefinierten Status bereitstellen. Anweisungen zum benutzerdefinierten Status werden den Schritten im Orchestrierungscode zugeordnet:
[FunctionName("ReserveTicket")]
public static async Task<bool> Run(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
string userId = context.GetInput<string>();
int discount = await context.CallActivityAsync<int>("CalculateDiscount", userId);
context.SetCustomStatus(new
{
discount = discount,
discountTimeout = 60,
bookingUrl = "https://www.myawesomebookingweb.com",
});
bool isBookingConfirmed = await context.WaitForExternalEvent<bool>("BookingConfirmed");
context.SetCustomStatus(isBookingConfirmed
? new {message = "Thank you for confirming your booking."}
: new {message = "The booking was not confirmed on time. Please try again."});
return isBookingConfirmed;
}
const df = require("durable-functions");
module.exports = df.orchestrator(function*(context) {
const userId = context.df.getInput();
const discount = yield context.df.callActivity("CalculateDiscount", userId);
context.df.setCustomStatus({
discount,
discountTimeout = 60,
bookingUrl = "https://www.myawesomebookingweb.com",
});
const isBookingConfirmed = yield context.df.waitForExternalEvent("bookingConfirmed");
context.df.setCustomStatus(isBookingConfirmed
? { message: "Thank you for confirming your booking." }
: { message: "The booking was not confirmed on time. Please try again." }
);
return isBookingConfirmed;
});
import azure.functions as func
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
userId = int(context.get_input())
discount = yield context.call_activity('CalculateDiscount', userId)
status = { 'discount' : discount,
'discountTimeout' : 60,
'bookingUrl' : "https://www.myawesomebookingweb.com",
}
context.set_custom_status(status)
is_booking_confirmed = yield context.wait_for_external_event('BookingConfirmed')
context.set_custom_status({'message': 'Thank you for confirming your booking.'} if is_booking_confirmed
else {'message': 'The booking was not confirmed on time. Please try again.'})
return is_booking_confirmed
main = df.Orchestrator.create(orchestrator_function)
param($Context)
$userId = $Context.Input -as [int]
$discount = Invoke-DurableActivity -FunctionName 'CalculateDiscount' -Input $userId
$status = @{
discount = $discount;
discountTimeout = 60;
bookingUrl = "https://www.myawesomebookingweb.com"
}
Set-DurableCustomStatus -CustomStatus $status
$isBookingConfirmed = Invoke-DurableActivity -FunctionName 'BookingConfirmed'
if ($isBookingConfirmed) {
Set-DurableCustomStatus -CustomStatus @{message = 'Thank you for confirming your booking.'}
} else {
Set-DurableCustomStatus -CustomStatus @{message = 'The booking was not confirmed on time. Please try again.'}
}
return $isBookingConfirmed
@FunctionName("ReserveTicket")
public boolean reserveTicket(
@DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
String userID = ctx.getInput(String.class);
int discount = ctx.callActivity("CalculateDiscount", userID, int.class).await();
ctx.setCustomStatus(new DiscountInfo(discount, 60, "https://www.myawesomebookingweb.com"));
boolean isConfirmed = ctx.waitForExternalEvent("BookingConfirmed", boolean.class).await();
if (isConfirmed) {
ctx.setCustomStatus("Thank you for confirming your booking.");
} else {
ctx.setCustomStatus("There was a problem confirming your booking. Please try again.");
}
return isConfirmed;
}
class DiscountInfo {
public DiscountInfo() { }
public DiscountInfo(int discount, int discountTimeout, String bookingUrl) {
this.discount = discount;
this.discountTimeout = discountTimeout;
this.bookingUrl = bookingUrl;
}
public int discount;
public int discountTimeout;
public String bookingUrl;
}
Abfragen des benutzerdefinierten Status mit HTTP
Das folgende Beispiel zeigt, wie benutzerdefinierte Statuswerte mithilfe der integrierten HTTP-APIs abgefragt werden können.
public static async Task SetStatusTest([OrchestrationTrigger] IDurableOrchestrationContext context)
{
// ...do work...
// update the status of the orchestration with some arbitrary data
var customStatus = new { nextActions = new [] {"A", "B", "C"}, foo = 2, };
context.SetCustomStatus(customStatus);
// ...do more work...
}
const df = require("durable-functions");
module.exports = df.orchestrator(function*(context) {
// ...do work...
// update the status of the orchestration with some arbitrary data
const customStatus = { nextActions: [ "A", "B", "C" ], foo: 2, };
context.df.setCustomStatus(customStatus);
// ...do more work...
});
import azure.functions as func
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
# ...do work...
custom_status = {'nextActions': ['A','B','C'], 'foo':2}
context.set_custom_status(custom_status)
# ...do more work...
main = df.Orchestrator.create(orchestrator_function)
@FunctionName("MyCustomStatusOrchestrator")
public void myCustomStatusOrchestrator(
@DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
// ... do work ...
// update the status of the orchestration with some arbitrary data
CustomStatusPayload payload = new CustomStatusPayload();
payload.nextActions = new String[] { "A", "B", "C" };
payload.foo = 2;
ctx.setCustomStatus(payload);
// ... do more work ...
}
class CustomStatusPayload {
public String[] nextActions;
public int foo;
}
Während der Ausführung der Orchestrierung können externe Clients diesen benutzerdefinierten Status abrufen:
GET /runtime/webhooks/durabletask/instances/instance123
Die benutzerdefinierten Statusnutzdaten sind auf 16 KB UTF-16-JSON-Text beschränkt. Es wird empfohlen, externen Speicher zu verwenden, wenn Sie eine größere Nutzlast benötigen.