Aktivitetshubbar i Durable Functions (Azure Functions)
En aktivitetshubb i Durable Functions är en representation av programmets aktuella tillstånd i lagringen, inklusive allt väntande arbete. När en funktionsapp körs lagras förloppet för orkestrerings-, aktivitets- och entitetsfunktioner kontinuerligt i aktivitetshubben. Detta säkerställer att programmet kan återuppta bearbetningen där det slutade, om det skulle behöva startas om efter att tillfälligt ha stoppats eller avbrutits av någon anledning. Dessutom kan funktionsappen skala beräkningsarbetarna dynamiskt.
Begreppsmässigt lagrar en aktivitetshubb följande information:
- Instanstillstånd för alla orkestrerings- och entitetsinstanser.
- De meddelanden som ska bearbetas, inklusive
- aktivitetsmeddelanden som representerar aktiviteter som väntar på att köras.
- alla instansmeddelanden som väntar på att levereras till instanser.
Skillnaden mellan aktivitets- och instansmeddelanden är att aktivitetsmeddelanden är tillståndslösa och därför kan bearbetas var som helst, medan instansmeddelanden måste levereras till en viss tillståndskänslig instans (orkestrering eller entitet) som identifieras av dess instans-ID.
Internt kan varje lagringsprovider använda en annan organisation för att representera instanstillstånd och meddelanden. Meddelanden lagras till exempel i Azure Storage-köer av Azure Storage-providern, men i relationstabeller av MSSQL-providern. Dessa skillnader spelar ingen roll när det gäller programmets design, men vissa av dem kan påverka prestandaegenskaperna. Vi diskuterar dem i avsnittet Representation in storage (Representation i lagring ) nedan.
Arbetsobjekt
Aktivitetsmeddelandena och instansmeddelandena i aktivitetshubben representerar det arbete som funktionsappen behöver bearbeta. Medan funktionsappen körs hämtar den kontinuerligt arbetsobjekt från aktivitetshubben. Varje arbetsobjekt bearbetar ett eller flera meddelanden. Vi särskiljer två typer av arbetsobjekt:
- Aktivitetsarbetsobjekt: Kör en aktivitetsfunktion för att bearbeta ett aktivitetsmeddelande.
- Orchestrator-arbetsobjekt: Kör en orkestrerings- eller entitetsfunktion för att bearbeta ett eller flera instansmeddelanden.
Arbetare kan bearbeta flera arbetsobjekt samtidigt, med förbehåll för de konfigurerade samtidighetsgränserna per arbetare.
När en arbetare har slutfört ett arbetsobjekt checkas effekterna tillbaka till aktivitetshubben. Dessa effekter varierar beroende på vilken typ av funktion som kördes:
- En slutförd aktivitetsfunktion skapar ett instansmeddelande som innehåller resultatet, adresserat till den överordnade orchestrator-instansen.
- En slutförd orkestreringsfunktion uppdaterar orkestreringstillståndet och historiken och kan skapa nya meddelanden.
- En slutförd entitetsfunktion uppdaterar entitetstillståndet och kan även skapa nya instansmeddelanden.
För orkestreringar representerar varje arbetsobjekt ett avsnitt av orkestreringens utförande. Ett avsnitt börjar när det finns nya meddelanden som orkestreraren ska bearbeta. Ett sådant meddelande kan tyda på att orkestreringen bör starta. eller så kan det tyda på att en aktivitet, ett entitetsanrop, entitetsanrop, timer eller suborchestration har slutförts; eller så kan den representera en extern händelse. Meddelandet utlöser ett arbetsobjekt som gör att orkestreraren kan bearbeta resultatet och fortsätta med nästa avsnitt. Avsnittet avslutas när orkestreraren antingen slutförs eller når en punkt där den måste vänta på nya meddelanden.
Körningsexempel
Överväg en fan-out-fan-in-orkestrering som startar två aktiviteter parallellt och väntar på att båda ska slutföras:
[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);
}
När orkestreringen har initierats av en klient bearbetas den av funktionsappen som en sekvens med arbetsobjekt. Varje slutfört arbetsobjekt uppdaterar statusen för aktivitetshubben när den checkas in. Det här är stegen:
En klient begär att starta en ny orkestrering med instans-ID "123". När klienten har slutfört den här begäran innehåller aktivitetshubben en platshållare för orkestreringstillståndet och ett instansmeddelande:
Etiketten
ExecutionStarted
är en av många typer av historikhändelser som identifierar de olika typerna av meddelanden och händelser som deltar i orkestreringens historik.En arbetare kör ett orkestreringsarbetsobjekt för att bearbeta meddelandet
ExecutionStarted
. Den anropar orchestrator-funktionen som börjar köra orkestreringskoden. Den här koden schemalägger två aktiviteter och slutar sedan att köras när den väntar på resultatet. När arbetaren har checkar in det här arbetsobjektet innehåller aktivitetshubbenKörningstillståndet är nu
Running
, två nyaTaskScheduled
meddelanden har lagts till och historiken innehåller nu de fem händelsernaOrchestratorStarted
,ExecutionStarted
,TaskScheduled
,TaskScheduled
,OrchestratorCompleted
. Dessa händelser representerar det första avsnittet av orkestreringens utförande.En arbetare kör ett aktivitetsarbetsobjekt för att bearbeta ett av meddelandena
TaskScheduled
. Den anropar aktivitetsfunktionen med indata "2". När aktivitetsfunktionen har slutförts skapas ettTaskCompleted
meddelande som innehåller resultatet. När arbetaren har checkar in det här arbetsobjektet innehåller aktivitetshubbenEn arbetare kör ett orkestreringsarbetsobjekt för att bearbeta meddelandet
TaskCompleted
. Om orkestreringen fortfarande cachelagras i minnet kan den bara återuppta körningen. Annars spelar arbetaren först upp historiken igen för att återställa orkestreringens aktuella tillstånd. Sedan fortsätter orkestreringen och levererar resultatet av aktiviteten. När du har fått det här resultatet väntar orkestreringen fortfarande på resultatet av den andra aktiviteten, så den slutar köras igen. När arbetaren har checkar in det här arbetsobjektet innehåller aktivitetshubbenOrkestreringshistoriken innehåller nu ytterligare tre händelser
OrchestratorStarted
, ,TaskCompleted
OrchestratorCompleted
. Dessa händelser representerar det andra avsnittet av orkestreringens utförande.En arbetare kör ett aktivitetsarbetsobjekt för att bearbeta det återstående
TaskScheduled
meddelandet. Den anropar aktivitetsfunktionen med indata "1". När arbetaren har checkar in det här arbetsobjektet innehåller aktivitetshubbenEn arbetare kör ett annat orkestreringsarbetsobjekt för att bearbeta meddelandet
TaskCompleted
. Orkestreringen slutförs när du har fått det andra resultatet. När arbetaren har checkar in det här arbetsobjektet innehåller aktivitetshubbenKörningstillståndet är nu
Completed
och orkestreringshistoriken innehåller nu ytterligare fyra händelserOrchestratorStarted
,TaskCompleted
,ExecutionCompleted
,OrchestratorCompleted
. Dessa händelser representerar det tredje och sista avsnittet av orkestreringens utförande.
Den slutliga historiken för orkestreringens körning innehåller sedan de 12 händelserna OrchestratorStarted
, , ExecutionStarted
TaskScheduled
, TaskScheduled
, OrchestratorCompleted
, OrchestratorStarted
, TaskCompleted
, OrchestratorCompleted
, OrchestratorStarted
, TaskCompleted
, , ExecutionCompleted
. OrchestratorCompleted
Anteckning
Schemat som visas är inte det enda: det finns många lite olika möjliga scheman. Om den andra aktiviteten till exempel slutförs tidigare kan båda TaskCompleted
instansmeddelandena bearbetas av ett enda arbetsobjekt. I så fall är körningshistoriken lite kortare eftersom det bara finns två avsnitt och innehåller följande 10 händelser: OrchestratorStarted
, ExecutionStarted
, TaskScheduled
, TaskScheduled
, OrchestratorCompleted
, OrchestratorStarted
, , TaskCompleted
, TaskCompleted
, , , ExecutionCompleted
, OrchestratorCompleted
.
Hantering av aktivitetshubben
Nu ska vi titta närmare på hur aktivitetshubbar skapas eller tas bort, hur du använder aktivitetshubbar korrekt när du kör flera funktionsappar och hur innehållet i aktivitetshubbar kan inspekteras.
Skapa och ta bort
En tom aktivitetshubb med alla nödvändiga resurser skapas automatiskt i lagringen när en funktionsapp startas första gången.
Om du använder Azure Storage-standardprovidern krävs ingen extra konfiguration. Annars följer du anvisningarna för att konfigurera lagringsproviders för att säkerställa att lagringsprovidern kan etablera och komma åt de lagringsresurser som krävs för aktivitetshubben korrekt.
Anteckning
Aktivitetshubben tas inte bort automatiskt när du stoppar eller tar bort funktionsappen. Du måste ta bort aktivitetshubben, dess innehåll eller det innehållande lagringskontot manuellt om du inte längre vill behålla dessa data.
Tips
I ett utvecklingsscenario kan du ofta behöva starta om från ett rent tillstånd. Om du vill göra det snabbt kan du bara ändra namnet på den konfigurerade aktivitetshubben. Detta tvingar fram skapandet av en ny, tom aktivitetshubb när du startar om programmet. Tänk på att gamla data inte tas bort i det här fallet.
Flera funktionsappar
Om flera funktionsappar delar ett lagringskonto måste varje funktionsapp konfigureras med ett separat namn på aktivitetshubben. Det här kravet gäller även för mellanlagringsplatser: varje mellanlagringsplats måste konfigureras med ett unikt namn på aktivitetshubben. Ett enda lagringskonto kan innehålla flera aktivitetshubbar. Den här begränsningen gäller vanligtvis även för andra lagringsleverantörer.
Följande diagram illustrerar en aktivitetshubb per funktionsapp i delade och dedikerade Azure Storage-konton.
Anteckning
Undantaget för delningsregeln för aktivitetshubben är om du konfigurerar appen för regional haveriberedskap. Mer information finns i artikeln om haveriberedskap och geodistribution .
Innehållsgranskning
Det finns flera vanliga sätt att inspektera innehållet i en aktivitetshubb:
- I en funktionsapp tillhandahåller klientobjektet metoder för att fråga instansarkivet. Mer information om vilka typer av frågor som stöds finns i artikeln Instanshantering .
- På samma sätt erbjuder HTTP-API :et REST-begäranden för att fråga orkestrerings- och entiteternas tillstånd. Mer information finns i HTTP API-referensen .
- Verktyget Durable Functions Monitor kan granska aktivitetshubbar och erbjuder olika alternativ för visuell visning.
För vissa lagringsproviders är det också möjligt att inspektera aktivitetshubben genom att gå direkt till den underliggande lagringen:
- Om du använder Azure Storage-providern lagras instanstillstånden i instanstabellen och den historiktabell som kan inspekteras med hjälp av verktyg som Azure Storage Explorer.
- Om du använder MSSQL-lagringsprovidern kan SQL-frågor och verktyg användas för att inspektera innehållet i aktivitetshubben i databasen.
Representation i lagring
Varje lagringsprovider använder en annan intern organisation för att representera uppgiftshubbar i lagringen. Att förstå den här organisationen, även om den inte behövs, kan vara användbart när du felsöker en funktionsapp eller när du försöker säkerställa prestanda, skalbarhet eller kostnadsmål. Vi förklarar därför kortfattat för varje lagringsprovider hur data organiseras i lagringen. Mer information om de olika alternativen för lagringsprovidern och hur de jämförs finns i Durable Functions lagringsproviders.
Azure Storage-provider
Azure Storage-providern representerar uppgiftshubben i lagringen med hjälp av följande komponenter:
- Två Azure-tabeller lagrar instanstillstånden.
- En Azure Queue lagrar aktivitetsmeddelandena.
- En eller flera Azure Queues lagrar instansmeddelandena. Var och en av dessa så kallade kontrollköer representerar en partition som tilldelas en delmängd av alla instansmeddelanden, baserat på hashen för instans-ID:t.
- Några extra blobcontainrar som används för att låna blobar och/eller stora meddelanden.
Till exempel innehåller en aktivitetshubb med PartitionCount = 4
namnet xyz
följande köer och tabeller:
Därefter beskriver vi dessa komponenter och vilken roll de spelar mer detaljerat.
Mer information om hur aktivitetshubbar representeras av Azure Storage-providern finns i dokumentationen för Azure Storage-providern .
Netherite Storage-provider
Netherite partitioneras alla aktivitetshubbens tillstånd i ett angivet antal partitioner. I lagring används följande resurser:
- En Azure Storage-blobcontainer som innehåller alla blobar, grupperade efter partition.
- En Azure-tabell som innehåller publicerade mått om partitionerna.
- Ett Azure Event Hubs namnområde för att leverera meddelanden mellan partitioner.
En aktivitetshubb med namnet mytaskhub
med PartitionCount = 32
representeras till exempel i lagring enligt följande:
Anteckning
Alla aktivitetshubbens tillstånd lagras i blobcontainern x-storage
. Tabellen DurableTaskPartitions
och EventHubs-namnområdet innehåller redundanta data: om innehållet går förlorat kan de återställas automatiskt. Därför är det inte nödvändigt att konfigurera Azure Event Hubs namnområde för att behålla meddelanden efter standardtidsdatum.
Netherite använder en mekanism för händelsekällor, baserat på en logg och kontrollpunkter, för att representera det aktuella tillståndet för en partition. Både blockblobar och sidblobar används. Det går inte att läsa det här formatet direkt från lagringen, så funktionsappen måste köras när du kör frågor mot instansarkivet.
Mer information om aktivitetshubbar för Netherite-lagringsprovidern finns i Task Hub-information för netherite-lagringsprovidern.
MSSQL-lagringsprovider
Alla aktivitetshubbens data lagras i en enda relationsdatabas med hjälp av flera tabeller:
- Tabellerna
dt.Instances
ochdt.History
lagrar instanstillstånden. - Tabellen
dt.NewEvents
lagrar instansmeddelandena. - Tabellen
dt.NewTasks
lagrar aktivitetsmeddelandena.
Om du vill göra det möjligt för flera aktivitetshubbar att samexistera oberoende av varandra i samma databas innehåller varje tabell en kolumn som en TaskHub
del av dess primärnyckel. Till skillnad från de andra två leverantörerna har MSSQL-providern inte ett begrepp för partitioner.
Mer information om uppgiftshubbar för MSSQL-lagringsprovidern finns i Task Hub-information för Microsoft SQL-lagringsprovidern (MSSQL).
Namn på aktivitetshubben
Aktivitetshubbar identifieras med ett namn som måste följa dessa regler:
- Innehåller endast alfanumeriska tecken
- Börjar med en bokstav
- Har en minsta längd på 3 tecken, maximal längd på 45 tecken
Namnet på aktivitetshubben deklareras i filen host.json , enligt följande exempel:
host.json (Functions 2.0)
{
"version": "2.0",
"extensions": {
"durableTask": {
"hubName": "MyTaskHub"
}
}
}
host.json (Functions 1.x)
{
"durableTask": {
"hubName": "MyTaskHub"
}
}
Aktivitetshubbar kan också konfigureras med hjälp av appinställningar, som du ser i följande host.json
exempelfil:
host.json (Functions 1.0)
{
"durableTask": {
"hubName": "%MyTaskHub%"
}
}
host.json (Functions 2.0)
{
"version": "2.0",
"extensions": {
"durableTask": {
"hubName": "%MyTaskHub%"
}
}
}
Namnet på aktivitetshubben anges till värdet för appinställningen MyTaskHub
. Följande local.settings.json
visar hur du definierar inställningen MyTaskHub
som samplehubname
:
{
"IsEncrypted": false,
"Values": {
"MyTaskHub" : "samplehubname"
}
}
Anteckning
När du använder distributionsplatser är det bästa praxis att konfigurera namnet på aktivitetshubben med hjälp av appinställningar. Om du vill se till att ett visst fack alltid använder en viss aktivitetshubb använder du appinställningarna "slot-sticky".
Förutom host.json kan även aktivitetshubbens namn konfigureras i bindningsmetadata för orkestreringsklienten . Detta är användbart om du behöver komma åt orkestreringar eller entiteter som finns i en separat funktionsapp. Följande kod visar hur du skriver en funktion som använder orchestration-klientbindningen för att arbeta med en aktivitetshubb som är konfigurerad som en appinställning:
[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);
}
Anteckning
Föregående exempel är för Durable Functions 2.x. För Durable Functions 1.x måste du använda DurableOrchestrationContext
i stället för IDurableOrchestrationContext
. Mer information om skillnaderna mellan versioner finns i artikeln Durable Functions versioner.
Anteckning
Du behöver bara konfigurera aktivitetshubbens namn i klientbindningsmetadata när du använder en funktionsapp för att få åtkomst till orkestreringar och entiteter i en annan funktionsapp. Om klientfunktionerna definieras i samma funktionsapp som orkestreringarna och entiteterna bör du undvika att ange aktivitetshubbens namn i bindningsmetadata. Som standard får alla klientbindningar sina metadata för aktivitetshubben från host.json-inställningarna .
Namn på aktivitetshubbar måste börja med en bokstav och bestå av endast bokstäver och siffror. Om inget anges används ett standardnamn för aktivitetshubben enligt följande tabell:
Beständig tilläggsversion | Standardnamn för aktivitetshubben |
---|---|
2.x | När den distribueras i Azure härleds namnet på aktivitetshubben från namnet på funktionsappen. När du kör utanför Azure är TestHubName standardnamnet för aktivitetshubben . |
1.x | Standardnamnet för aktivitetshubben för alla miljöer är DurableFunctionsHub . |
Mer information om skillnaderna mellan tilläggsversioner finns i artikeln Durable Functions versioner.
Anteckning
Namnet är det som skiljer en aktivitetshubb från en annan när det finns flera aktivitetshubbar i ett delat lagringskonto. Om du har flera funktionsappar som delar ett delat lagringskonto måste du uttryckligen konfigurera olika namn för varje aktivitetshubb i host.json-filerna . Annars konkurrerar flera funktionsappar med varandra om meddelanden, vilket kan resultera i odefinierat beteende, inklusive orkestreringar som oväntat "fastnar" i Pending
tillståndet eller Running
.