DevelopmentDurable Functions, Azure Functions met state

De meeste ontwikkelaars die gebruik maken van Azure zullen wel bekend zijn met de term ‘Azure Functions’. Wie  hier nog niet mee bekend is, raad ik aan om eerst te kijken naar de Microsoft documentatie over Azure Functions.

Azure Functions worden meestal gebruikt voor het uitvoeren van kleine stukjes code, zo geheten ‘functions’. Hierbij hoef je als ontwikkelaar geen rekening te houden met de applicatie infrastructuur. Azure voorziet op ieder moment in precies voldoende servercapaciteit om je applicatie schaalbaar draaiende te houden. Om deze reden valt Azure Functions onder de categorie ‘Serverless Computing’. Het bijkomende voordeel is dat je alleen betaalt voor het aantal maal dat je function wordt aangeroepen. Dit kan een grote kostenbesparing opleveren ten opzichten van een bijv. een App Service.

De meest gebruikte use case voor Azure Functions is ook het aanroepen van een function om bepaalde taken uit te voeren. Zoals het aanroepen van een andere API of het aansturen van andere services. Als voorbeeld nemen we het boeken van een vakantie en dan specifiek het verblijf en de vlucht. Als we gebruik maken van Azure Functions zal het er ongeveer uit zien zoals in figuur 1.

 

Fan-out / fan-in pattern
Figuur 1: Fan-out / fan-in pattern

De ‘Boek vakantie’ activeert een event die twee verschillende functies zal aanroepen. Om uiteindelijk de kosten te kunnen berekenen, moeten de resultaten van de functions ergens tussentijds worden opgeslagen. De functions worden apart van elkaar uitgevoerd in willekeurige volgorde. Dit vereist veel specifieke code om de ‘state’ tussen de twee functions te bewaren. Als we meer functions koppelen, zal de complexiteit alleen maar groter worden en dan hebben we het nog niet over wanneer één van de functies een fout retourneert of wanneer er sprake is van ‘race condition’. Dit probleem kunnen we oplossen door gebruik te maken van Durable Functions.

Azure Durable Functions

Durable Functions is een extensie op Azure Functions. Eén van de voordelen van Durable Functions is de ondersteuning van ‘statefull workflows’ in een Serverless omgeving. Dit houdt in, dat het mogelijk is om ‘state’ bij te houden. Durable Functions schalen net als Azure Functions en hebben ook dezelfde kostenbesparende voordelen. Ze maken het mogelijk om complexe workflows te implementeren in Azure.

Eén van de voordelen van Durable Functions is dat je asynchrone operaties kan afwachten en op basis van het resultaat een nieuwe serie aan taken kan starten. Ook is het mogelijk om langlopende handelingen uit te voeren. Wanneer een function moet wachten op een resultaat omdat die vertraagd binnen komt, kan de ‘state’ van de function als een checkpoint worden opgeslagen in Azure. Dit noemen ze ‘dehydrate’ van een function. Wanneer de function weer verder kan met zijn taak zal de ‘state’ worden teruggezet, dit heet ‘rehydrate’.

Durable function types

Een Durable Function kan een van de volgende drie types zijn:

  • Client: Het beginpunt van een Durable function (Trigger);
  • Orchestrator: Beschrijft hoe en in welke volgorde de acties worden uitgevoerd (workflow);
  • Activity: Bevat het werk dat verricht moet worden (Unit of work).

Om het probleem in figuur 1 op te lossen, gaan we gebruik maken van de drie Durable function types.

Als eerste zullen we gebruik maken van de client function. Een client function kan op veel verschillende manieren gestart worden, zoals een HttpTrigger, QueueTrigger of één van de andere triggers die Azure Functions aanbiedt.

De client function zal de workflow starten door de orchestration function aan te roepen. De taak van een orchestrator is om het werk te delegeren naar functions die geen ‘state’ kunnen bijhouden. De orchestrator zal de workflow beheren en zijn geschiedenis. De orchestrator heeft functions nodig van het type ‘activity’ om aan te sturen. Als we weer het voorbeeld uit figuur 1 nemen, kunnen we ‘activity’ functions maken voor ‘Boek vakantie’, ‘Boek vlucht’ en ‘Boek hotel’.

Durable function
Figuur 2: Durable function

In figuur 2 is te zien hoe de activity functions worden aangestuurd door de orchestration function ‘Plan vakantie’. De activity functions worden aangestuurd en rapporteren hun resultaat terug naar de orchestration function. Deze zal de ‘state’ van de workflow bijhouden en het resultaat van de drie functions gebruiken om, in dit geval, de kosten te rapporteren.

Hoe maak je een Durable Function?

Het maken van een durable function is niet ingewikkeld. In principe zijn het allemaal Azure Functions die ieder hun eigen type meekrijgen als parameter. Zo weet Azure om wat voor soort function het gaat en welke eigenschappen de function bevat.

Client function

Als eerste wordt de client function aangemaakt, dit is het startpunt die de orchestrator function (workflow) zal activeren. In dit geval zal de function starten wanneer de URL van de function wordt aangeroepen (HttpTrigger).

Client function
Figuur 3: Client function

Grotendeels is dit een standaard function, echter door ‘DurableClient’ mee te geven als parameter weet Azure dat het om een client function gaat en het een startpunt is van een durable function.

De client function zal de workflow oftewel orchestration function aanroepen om de workflow te starten.

Orchestrator Function

In onderstaand figuur is de orchestrator function uitgewerkt. Deze wordt gekenmerkt door ‘OrchestrationTrigger’ mee te geven als parameter van de function.

Orchestrator function
Figuur 4: Orchestrator function

Vanuit de orchestrator worden meerdere activity functions aangeroepen die hun resultaat zullen teruggeven aan de orchestrator function. Zo is te zien dat we de ‘Boek_vakantie, vlucht en zon’ activiteiten aanroepen.

Activity Function

Iedere activity function is een losstaande function met zijn eigen business logica die wordt uitgevoerd. In figuur 5 zien we een activity function zoals we gebruiken in ons voorbeeld.

Figuur 5: Activity function

Een activity function kenmerkt zich door ‘ActivityTrigger’ mee te geven als parameter. In dit geval is de logica in de activity function beperkt gebleven, echter kan je net als in een normale function gebruik maken van alle functionaliteiten die een standaard function aanbied.

De eerder genoemde problemen zoals race condition en foutafhandeling zijn eenvoudig op te lossen met een Durable function. In de orchestrator function kunnen we activity functions asynchroon maken en wachten op het resultaat totdat we er verder mee gaan werken. Mocht een van de activity functions een fout retourneren, dan kunnen we deze fout in de orchestrator function opvangen en een alternatieve flow starten indien nodig.

Er zijn nog veel meer mogelijkheden te bedenken met Durable Functions. Wil je door deze blog nog meer te weten komen over Durable Functions? Dan raad ik je ook aan om de documentatie van Microsoft door te lezen. Hier worden aan de hand van duidelijke voorbeeld applicaties de verschillende use cases en mogelijkheden van Durable Functions toegelicht.

Mitchel Hulst, Software developer