Duurzame indelingen

Durable Functions is een uitbreiding op Azure Functions. U kunt een orchestratorfunctie gebruiken om de uitvoering van andere duurzame functies in een functie-app in te delen. Orchestratorfuncties hebben de volgende kenmerken:

  • Met orchestratorfuncties worden functiewerkstromen gedefinieerd met behulp van procedurele code. Er zijn geen declaratieve schema's of ontwerpers nodig.
  • Orchestratorfuncties kunnen op synchrone en asynchrone wijze andere duurzame functies aanroepen. Uitvoer van aangeroepen functies kan betrouwbaar worden opgeslagen in lokale variabelen.
  • Orchestratorfuncties zijn duurzaam en betrouwbaar. Tijdens de uitvoering worden automatisch controlepunten gemaakt wanneer de functie wacht of onderbroken wordt. Er gaat nooit lokale status verloren wanneer het proces recyclet of de VM opnieuw wordt opgestart.
  • Orchestratorfuncties kunnen langdurig worden uitgevoerd. De totale levensduur van een indelingsinstantie kan seconden, dagen, maanden of oneindig zijn.

In dit artikel vindt u een overzicht van orchestratorfuncties en hoe ze kunnen bijdragen tot het oplossen van verschillende problemen bij het ontwikkelen van apps. Als u nog niet bekend bent met de typen functies die beschikbaar zijn in een Durable Functions-app, leest u eerst het artikel Durable Function-typen.

Identiteit van indelingen

Elk instantie van een indeling heeft een instantie-id. Standaard is elke instantie-id een automatisch gegenereerde, unieke id. Instantie-id's kunnen echter ook een door de gebruiker gegenereerde tekenreekswaarde zijn. Elke instantie-id van de indeling moet uniek zijn binnen een taakhub.

Hier volgen enkele regels voor instantie-id's:

  • Exemplaar-id's moeten tussen 1 en 100 tekens zijn.
  • Instantie-id's mogen niet beginnen met @.
  • Instantie-id's mogen de tekens /, \, # of ? niet bevatten.
  • Instantie-id's mogen geen besturingstekens bevatten.

Notitie

Het wordt in het algemeen aangeraden om waar mogelijk automatisch gegenereerde instantie-id's te gebruiken. Door de gebruiker gegenereerde instantie-id's zijn bedoeld voor scenario's waarbij een een-op-een-toewijzing bestaat tussen een indelingsinstantie en een bepaalde externe toepassingsspecifieke entiteit, zoals een aankooporder of een document.

De daadwerkelijke afdwinging van regels voor tekenbeperking kan ook variëren, afhankelijk van de opslagprovider die door de app wordt gebruikt. Om ervoor te zorgen dat het gedrag en de compatibiliteit juist zijn, wordt u sterk aangeraden de eerder vermelde exemplaar-id-regels te volgen.

De instantie-id van een indeling is een vereiste parameter voor de meeste beheerbewerkingen voor instanties. Ze zijn ook belangrijk voor diagnostische gegevens, zoals het zoeken in traceringsgegevens van indelingen in Application Insights voor probleemoplossing of analyses. Daarom is het raadzaam om gegenereerde instantie-id's op te slaan op een externe locatie (bijvoorbeeld een database of een toepassingslogboek), waar u ze later eenvoudig kunt naslaan.

Betrouwbaarheid

Orchestratorfuncties behouden op betrouwbare wijze de status van de uitvoering door gebruik te maken van een ontwerppatroon in de vorm van gebeurtenisbronnen. In plaats van de huidige status van een indeling rechtstreeks op te slaan, gebruikt het duurzame taakframework een archief waaraan alleen iets kan worden toegevoegd (alleen-toevoegenarchief) om de volledige reeks acties vast te leggen die door de functie-indeling wordt uitgevoerd. Een alleen-toevoegenarchief heeft veel voordelen ten opzichte van het 'dumpen' van de volledige status tijdens runtime. Voordelen zijn onder andere betere prestaties, schaalbaarheid en reactiesnelheid. U krijgt ook consistentie van gebeurtenissen voor transactionele gegevens en volledige audittrails en een volledige geschiedenis. Betrouwbare compenserende acties worden door de audittrails ondersteund.

Durable Functions maakt op transparante wijze gebruik van gebeurtenisbronnen. Op de achtergrond geeft de operator await (C#) of yield (JavaScript/Python) in een orchestratorfunctie de controle over de orchestrator-thread terug aan de dispatcher van het duurzame taakframework. In het geval van Java is er geen speciaal taalwoord. In plaats daarvan zal het aanroepen van .await() een taak via een aangepaste Throwableregel terug naar de dispatcher leiden. De dispatcher voert vervolgens nieuwe acties door die de orchestratorfunctie voor opslag heeft gepland (zoals het aanroepen van een of meer onderliggende functies of het plannen van een duurzame timer). Met de transparante doorvoeractie wordt de uitvoeringsgeschiedenis van het indelingsexemplaar bijgewerkt door alle nieuwe gebeurtenissen toe te voegen aan de opslag, net als bij een alleen-toevoegend logboek. Op dezelfde manier worden met de doorvoeractie berichten in de opslag gemaakt om de werkelijke hoeveelheid werk te plannen. Op dit moment kan de orchestratorfunctie uit het geheugen worden verwijderd. Durable Functions maakt standaard gebruik van Azure Storage als runtimestatusopslag, maar andere opslagproviders worden ook ondersteund.

Wanneer een indelingsfunctie meer werk heeft gekregen (bijvoorbeeld wanneer er een antwoordbericht wordt ontvangen of er een duurzame timer verloopt), wordt de volledige functie door de orchestrator geactiveerd en vanaf het begin opnieuw uitgevoerd om de lokale status opnieuw op te bouwen. Als de code tijdens het opnieuw afspelen een functie wil aanroepen (of andere asynchrone werkzaamheden wil uitvoeren), wordt de uitvoeringsgeschiedenis van de huidige indeling door het duurzame taakframework geraadpleegd. Als wordt vastgesteld dat de activiteitsfunctie al is uitgevoerd en een resultaat heeft opgeleverd, wordt het resultaat van die functie opnieuw afgespeeld en blijft de orchestratorcode actief. Het opnieuw afspelen gaat door totdat de functiecode wordt voltooid of totdat er nieuw asynchroon werk is gepland.

Notitie

De code van de orchestratorfunctie moet deterministisch zijn opdat het nieuwe afspeelpatroon correct en betrouwbaar kan functioneren. Niet-deterministische orchestratorcode kan leiden tot runtimefouten of ander onverwacht gedrag. Zie de documentatie over codecodebeperkingen voor orchestratorfuncties voor meer informatie over codebeperkingen voor orchestratorfuncties.

Notitie

Als een orchestratorfunctie logboekberichten verzendt, kan het gedrag van het opnieuw afspelen ertoe leiden dat er dubbele logboekberichten worden verzonden. Zie het onderwerp Logboekregistratie voor meer informatie over waarom dit gedrag optreedt en hoe u dit kunt omzeilen.

Indelingsgeschiedenis

Het gedrag van gebeurtenisbronnen van het duurzame taakframework is nauw gekoppeld aan de orchestratorfunctiecode die u schrijft. Stel dat u een orchestratorfunctie voor het koppelen van activiteiten hebt, zoals de volgende orchestratorfunctie:

Notitie

Versie 4 van het Node.js programmeermodel voor Azure Functions is algemeen beschikbaar. Het nieuwe v4-model is ontworpen voor een flexibelere en intuïtievere ervaring voor JavaScript- en TypeScript-ontwikkelaars. Meer informatie over de verschillen tussen v3 en v4 in de migratiehandleiding.

In de volgende codefragmenten geeft JavaScript (PM4) het programmeermodel V4 aan, de nieuwe ervaring.

[FunctionName("HelloCities")]
public static async Task<List<string>> Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var outputs = new List<string>();

    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

    // returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
    return outputs;
}

Wanneer een activiteitsfunctie is gepland, controleert het Durable Task Framework de uitvoeringsstatus van de functie naar een duurzame opslagback-end (Standaard Azure Table Storage). Deze status wordt de indelingsgeschiedenis genoemd.

Geschiedenistabel

Normaal gesproken wordt door het duurzame taakframework op elk controlepunt het volgende uitgevoerd:

  1. Hiermee wordt de uitvoeringsgeschiedenis opgeslagen in duurzame opslag.
  2. Berichten voor functies die de orchestrator wil aanroepen, worden in de wachtrij geplaatst.
  3. Enqueues berichten voor de orchestrator zelf, bijvoorbeeld duurzame timerberichten.

Zodra het controlepunt is voltooid, kan de orchestratorfunctie uit het geheugen worden verwijderd totdat er meer werk te doen.

Notitie

Azure Storage biedt geen transactionele garanties voor het opslaan van gegevens in tabelopslag en wachtrijen. Voor het afhandelen van fouten gebruikt de Durable Functions Azure Storage-provideruiteindelijke consistentiepatronen . Deze patronen zorgen ervoor dat er geen gegevens verloren gaan als er midden in een controlepunt een storing optreedt in. Alternatieve opslagproviders, zoals de DURABLE Functions MSSQL-opslagprovider, kunnen sterkere consistentiegaranties bieden.

Na voltooiing ziet de geschiedenis van de eerder weergegeven functie er ongeveer uit zoals in de volgende tabel in Azure Table Storage (in de afbeelding voor de duidelijkheid afgekort):

PartitionKey (InstanceId) EventType Tijdstempel Invoer Naam Resultaat Status
eaee885b ExecutionStarted 2021-05-05T18:45:28.852Z Nul HelloCities
eaee885b OrchestratorStarted 2021-05-05T18:45:32.362Z
eaee885b TaskScheduled 2021-05-05T18:45:32.670Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:32.670Z
eaee885b TaskCompleted 2021-05-05T18:45:34.201Z """Hello Tokyo!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:34.232Z
eaee885b TaskScheduled 2021-05-05T18:45:34.435Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:34.435Z
eaee885b TaskCompleted 2021-05-05T18:45:34.763Z """Hello Seattle!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:34.857Z
eaee885b TaskScheduled 2021-05-05T18:45:34.857Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:34.857Z
eaee885b TaskCompleted 2021-05-05T18:45:34.919Z """Hello London!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:35.032Z
eaee885b OrchestratorCompleted 2021-05-05T18:45:35.044Z
eaee885b ExecutionCompleted 2021-05-05T18:45:35.044Z "[""Hello Tokyo!"",""Hello Seattle!"",""Hello London!""]" Voltooid

Enkele opmerkingen over de kolomwaarden:

  • PartitionKey: bevat de exemplaar-id van de indeling.
  • EventType: Vertegenwoordigt het type gebeurtenis. Hier vindt u gedetailleerde beschrijvingen van alle gebeurtenistypen voor geschiedenis.
  • Tijdstempel: de UTC-tijdstempel van de geschiedenis gebeurtenis.
  • Naam: De naam van de functie die is aangeroepen.
  • Invoer: De JSON-indelingsinvoer van de functie.
  • Resultaat: De uitvoer van de functie, dat wil gezegd de retourwaarde.

Waarschuwing

Hoewel deze tabel als een hulpprogramma voor foutopsporing kan worden gebruikt, moet u er niet afhankelijk van worden. De tabel kan veranderen naarmate de Durable Functions-uitbreiding zich ontwikkelt.

Telkens wanneer de functie wordt hervat nadat is gewacht totdat een taak is voltooid, voert het Durable Task Framework de orchestrator-functie opnieuw uit. Bij elke nieuwe uitvoering wordt de uitvoeringsgeschiedenis geraadpleegd om te bepalen of de huidige asynchrone taak is voltooid. Als in de uitvoeringsgeschiedenis wordt aangegeven dat de taak al is voltooid, wordt de uitvoer van die taak opnieuw afgespeeld en naar de volgende taak verplaatst. Dit proces wordt voortgezet totdat de volledige uitvoeringsgeschiedenis opnieuw is afgespeeld. Zodra de huidige uitvoeringsgeschiedenis opnieuw is afgespeeld, zijn de lokale variabelen hersteld naar hun vorige waarden.

Functies en patronen

In de volgende secties worden de functies en patronen van orchestratorfuncties beschreven.

Onderliggende indelingen

Orchestratorfuncties kunnen activiteitsfuncties aanroepen, maar ook andere orchestratorfuncties. U kunt bijvoorbeeld een grotere indeling op basis van een bibliotheek van orchestratorfuncties bouwen. U kunt ook meerdere instanties van een orchestratorfunctie parallel uitvoeren.

Zie het artikel Subindelingen voor meer informatie en voorbeelden.

Duurzame timers

Indelingen kunnen duurzame timers plannen voor het implementeren van vertragingen of het instellen van time-outverwerking voor asynchrone acties. Gebruik duurzame timers in orchestratorfuncties in plaats van taaleigen 'slaapstand'-API's.

Zie het artikel Duurzame timers voor meer informatie en voorbeelden.

Externe gebeurtenissen

Orchestratorfuncties kunnen wachten op externe gebeurtenissen om een indelingsinstantie bij te werken. Deze Durable Functions-functie is vaak handig voor het verwerken van een menselijke interactie of andere externe callbacks.

Zie het artikel Externe gebeurtenissen voor meer informatie en voorbeelden.

Foutafhandeling

Orchestratorfuncties kunnen de functies voor foutafhandeling van de programmeertaal gebruiken. Bestaande patronen als try/catch worden ondersteund in indelingscode.

Orchestratorfuncties kunnen ook beleid voor opnieuw proberen toevoegen aan de activiteits- of suborchestratorfuncties die ze aanroepen. Als een activiteits- of suborchestratorfunctie mislukt met een uitzondering, kan het opgegeven beleid voor opnieuw proberen automatisch worden vertraagd en de uitvoering een bepaald aantal keren opnieuw worden uitgevoerd.

Notitie

Als er sprake is van een onverwerkte uitzondering in een orchestratorfunctie, wordt de orchestratorinstantie voltooid met status Failed. Een orchestratorinstantie kan niet opnieuw worden uitgevoerd als deze is mislukt.

Zie het artikel Foutafhandeling voor meer informatie en voorbeelden.

Kritieke secties (Durable Functions 2.x, momenteel alleen .NET)

Indelingsinstanties bestaan uit één thread. U hoeft zich dus geen zorgen te maken over racevoorwaarden binnen een indeling. Racevoorwaarden zijn echter mogelijk wanneer indelingen met externe systemen communiceren. Voor het beperken van racevoorwaarden bij interactie met externe systemen kunnen orchestratorfuncties kritieke secties definiëren met behulp van een LockAsync-methode in .NET.

De volgende voorbeeldcode toont een orchestratorfunctie die een kritieke sectie definieert. De kritieke sectie wordt geactiveerd met behulp van de LockAsync-methode. Voor deze methode moeten een of meer verwijzingen naar een duurzame entiteit worden doorgegeven, wat de vergrendelingsstatus duurzaam beheert. De code in de kritieke sectie kan per keer slechts door één instantie van deze indeling worden uitgevoerd.

[FunctionName("Synchronize")]
public static async Task Synchronize(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var lockId = new EntityId("LockEntity", "MyLockIdentifier");
    using (await context.LockAsync(lockId))
    {
        // critical section - only one orchestration can enter at a time
    }
}

Een of meer duurzame vergrendelingen worden door LockAsync verkregen en geretourneerd als een IDisposable, wat de kritieke sectie beëindigd (indien verwijderd). Dit IDisposable-resultaat kan worden gebruikt in combinatie met een using-blok om een syntactische weergave van de kritieke sectie te krijgen. Wanneer een orchestratorfunctie naar een kritieke sectie overgaat, kan slechts één instantie dat codeblok uitvoeren. Alle andere instanties die naar de kritieke sectie willen overgaan, worden geblokkeerd totdat de vorige instantie de kritieke sectie verlaat.

De kritieke sectie is ook handig voor het coördineren van wijzigingen aan duurzame entiteiten. Zie het onderwerp Duurzame entiteiten - Entiteitscoördinatie voor meer informatie over kritieke secties.

Notitie

Kritieke secties zijn beschikbaar in Durable Functions 2.0. Momenteel implementeren alleen .NET in-proc-indelingen deze functie. Entiteiten en kritieke secties zijn nog niet beschikbaar in Durable Functions voor dotnet-geïsoleerde werkrol.

HTTP-eindpunten aanroepen (Durable Functions 2.x)

Orchestratorfuncties zijn niet toegestaan voor I/O, zoals beschreven in Codebeperkingen voor orchestratorfuncties. Voor deze beperking kan als tijdelijke oplossing de code worden verpakt die I/O in een activiteitsfunctie moet uitvoeren. Indelingen die communiceren met externe systemen gebruiken vaak activiteitsfuncties om HTTP-aanroepen te maken en het resultaat naar de indeling te retourneren.

Om dit algemene patroon te vereenvoudigen, kunnen orchestratorfuncties de CallHttpAsync-methode gebruiken om rechtstreeks HTTP-API's aan te roepen.

[FunctionName("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Uri url = context.GetInput<Uri>();

    // Makes an HTTP GET request to the specified endpoint
    DurableHttpResponse response = 
        await context.CallHttpAsync(HttpMethod.Get, url);

    if ((int)response.StatusCode == 400)
    {
        // handling of error codes goes here
    }
}

Naast het ondersteunen van elementaire voor aanvraag-/antwoordpatronen ondersteunt de methode automatische verwerking van veelvoorkomende asynchrone HTTP 202-navraagpatronen en ondersteunt het tevens verificatie met externe services met behulp van beheerde identiteiten.

Zie het artikel HTTP-kenmerken voor meer informatie en voor meer gedetailleerde voor beelden.

Notitie

Het rechtstreeks aanroepen van HTTP-eindpunten vanuit orchestratorfuncties is mogelijk in Durable Functions 2.0 en hoger.

Meerdere parameters doorgeven

Het is niet mogelijk om rechtstreeks meerdere parameters aan een activiteitsfunctie door te geven. Het wordt aangeraden een matrix met objecten of samengestelde objecten door te geven.

In .NET kunt u ook ValueTuple-objecten gebruiken. In het volgende voorbeeld worden nieuwe functies van ValueTuple toegevoegd met C# 7:

[FunctionName("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string major = "ComputerScience";
    int universityYear = context.GetInput<int>();

    object courseRecommendations = await context.CallActivityAsync<object>(
        "CourseRecommendations",
        (major, universityYear));
    return courseRecommendations;
}

[FunctionName("CourseRecommendations")]
public static async Task<object> Mapper([ActivityTrigger] IDurableActivityContext inputs)
{
    // parse input for student's major and year in university
    (string Major, int UniversityYear) studentInfo = inputs.GetInput<(string, int)>();

    // retrieve and return course recommendations by major and university year
    return new
    {
        major = studentInfo.Major,
        universityYear = studentInfo.UniversityYear,
        recommendedCourses = new []
        {
            "Introduction to .NET Programming",
            "Introduction to Linux",
            "Becoming an Entrepreneur"
        }
    };
}

Volgende stappen