This document discusses Durable Functions, which allow for writing long-running serverless workflows in Azure Functions. It describes how Durable Functions enable orchestrating function chains, fan-out/fan-in patterns, stateful singletons, and human interactions. It also covers key concepts like event sourcing, the durable task framework, and constraints around orchestration code.
14. Event Sourcing
• Does not simply persist the current state
• Uses an append-only store to record the full series of actions
• Kind of like Redux
15. Presentation
Cart created
Item 1 added
Item 2 added
Item 1 removed
Shipping information added
Event Store
Materialized View
External
systems
Cart ID
Date
Items
Query state
of entity
Replay events
Publish events
16. Benefits of Event Sourcing
• Performance
• Scalability
• Responsiveness
• Consistency for transactional data
• Full audit trails/history
18. Orchestration code constraints
• Must be deterministic
• Non-blocking
• Only async operations in DurableOrchestrationContext
• No other input/output bindings
• Infinite loops should be avoided
Apply only to orchestration functions and not activity functions!
Hello everyone, my name is Matti Petrelius
I’m going to be talking about Durable Functions that is a new extension to Azure Functions
I work for a company called Devisioona and we are in fact hiring
We do a lot of different kind of software projects from Integration and IoT to web and mobile applications
Most of our projects have something to do with Azure
We are looking for good people, talented coders and other IT-professionals
If you’re interest you should go check out our website at www.devisioona.fi and fill out a form and we will be in contact with you!
Durable Functions is something new in the Azure Serverless offering and fits it really well
Serverless is a terrible name, but it is an awesome technology
Serverless allows you to only pay for what you use in the cloud
And it does all the boring boilerplate stuff for you and let’s you concentrate on the code that is valuable to your business
What Azure Functions is is probably best described as Azure’s offering of Functions as a Service
Allows you to run independent function sized event-based pieces of code if the cloud without having to deal with the infrastructure
Similar to AWS Lambda or Google Cloud Functions
One of the most exciting new services on Azure
Announced at Build 2016 and has been continuosly evolving ever since
Azure Functions and serverless in general are great technologies but they are not without some problems
If you have ever used Azure Functions in real-life scenarios you have probably run into situations that are difficult to implement with the current tooling
First if you run just a single independent function everything is simple
But when you have multiple functions that are somehow dependent on each other thing start to get complicated
Going from a single monolith application to small function size nanoservices means there’s a lot more stuff to take care of
This requires orchestration and coordination
It is possible to handle this with traditional functions but it requires a lot of work
Also state and handling it is difficult with just regular Azure Functions
First of all normal Azure Functions are stateless
If you want to share state with other functions you have to persist it somewhere
If there are errors or the VM is shutdown for some reason the state can be lost and you may have to restart the whole process
Last but not least having long running functions is difficult if not impossible at the moment
The time limit for Azure Functions was increased from 5 minutes to 10 minutes but still you cannot have a regular function running longer than that
Also having long running functions kind of conflicts with the idea of functions being event based and only running when needed
And if an exception occurs or the function gets shut down it might be difficult to know what the state was when it was stopped
And the answer to these problems is of course Durable Functions
It literally describes itself as a long-running stateful orchestration
What is important to understand about Durable Functions is that
They don’t magically make regular functions long-running and stateful
Regular functions are called activity functions in Durable Functions land and have the limitations of being stateless and 10 minute running time
But what is different is that Durable Functions introduce orchestrator functions that do not have these limitations
The way you manage these orchestrations in Durable Functions is by writing C# code, no graphical UI or magical JSON files are needed
What the orchestrations for example can do is to call other functions asynchronously or synchronously and saving their output to local variables
And in the same way that Azure Functions is basically WebJobs as a Service, Durable Functions is actually Durable Task Framework as a Service
So Durable Task Framework is what allows writing long running persistent workflows in C# using the async/await capabilities
It is heavily used at Microsoft and other companies to automate mission-critical processes
And it’s a really good fit for the serverless Azure Functions environment
The primary use case for Durable Functions is simplifying complex, stateful coordination problems in serverless application
Here are some of the most common coordination patterns
You could implement at least some of these with regular Azure Functions but Durable Functions makes it a lot more less painful
During this talk I will go through all of these four patterns and highlight all the interesting parts
Let’s start of with Function Chaining
It is a very simple pattern where we execute functions in a sequence so that usually the output of the previous function is used as the input of the next function
Finally the output from the last function is returned from the orchestration as an output
You could implement this pattern with just regular Azure Functions but Durable Functions makes it very easy
Here we have all the code needed for a simple Function Chaining pattern
There are two functions and the first one is an orchestrator function and the second one is an activity function
First I would like to point out that the orchestrator function gets an orchestration trigger and activity function gets an activity trigger
These are new trigger types introduced by the Durable Functions
Also the terms orchestrator function and activity function are important in Durable Functions, Orchestrator functions do the orchestration and activity functions are functions that the orchestrator function can call, I will be using these terms a lot during this talk so I want to make sure they are clear
The next thing to notice is this await ctx.CallFunctionAsync call here, There is actually quite a lot going on here
First it calls the activity function named E1_SayHello but it also checkpoints the state of the orchestration function because in an orchestration function each time an external resource is awaited the current state is persisted
And the way that these checkpoints are made is with a pattern called Event Sourcing
Some of you might not be that familiar with event sourcing pattern so we should probably go through a little bit about what it means
Instead of simply persisting all of the current state with a CRUD-style pattern we have a append-only store that we send a series of actions to
These actions describe that changes made to the state and can be replayed to get back the current state
If you are familiar with front-end web development then you might be familiar with Redux which is not too far from event sourcing pattern
Here’s a simple example of a shopping cart implemented with the Event Sourcing Pattern
First the presentation layer send actions to the event store that describe how what the user does is changing the state of the cart
The cart is created, two items are added, one items is removed and then some shipping information is added
These actions are persisted in the event store but they are also published so that materialized views can be made of them for the presentation layer to use
Also external systems and applications can subscribe to get the published events
And what you can also do is to simply replay the events in the event store to get the current state
There are some clear benefits of using Event Sourcing
First of all performance is better than in traditional CRUD because you don’t have to directly access the data store
It is more scalable because dealing with concurrent updates is easier
Applications are more responsive because the entire state is not always dumped and events are handled in the background
Consistency is also easier to achieve because of the publishing of the events
And the event store can also work as a log of everything that has been done with the data
Let’s look at what happens in Durable Functions when an orchestrator function calls an activity function
First orchestrator function calls CallFunctionAsync and yields control to the Durable Task Framework Dispatcher
Durable Task Framework then makes a commit which means the action is appended to the execution history and the actual task of calling the activity function is added to queue
After that the orchestrator function can be unloaded from memory
Then when the result from the activity function is received the result is added to the execution history and the orchestrator function will be re-executed from start
So the CallFunctionAsync method is called again but this time the Durable Task Framework will check if the function has already executed
And since it has been, the result can be immediately returned and replayed by the orchestration function
I think this whole automatic checkpointing is an awesome feature and makes using Azure Functions a lot more reliable
Because of this use of the event sourcing pattern and replaying of the functions there are limitations to what you can do in orchestrator functions
First of all orchestrator code must be deterministic because the values have to be the same on each replay
This means there cannot be calls to get the current date or time, generating random numbers or ids or calling remote endpoints
Because the orchestration code runs on a single thread there should be no blocking code like for example using Thread.Sleep
You cannot also call other async operations than the ones exposed by the DurableOrchestrationContext because they might schedule other threads the orchestration thread cannot interact with
And for the same reason orchestrator functions should never have other input or output bindings than the orchestrator trigger
Because Durable Task Framework saves the execution history as the orchestration function progresses infinite loops should be avoided or they might run out of memory
These limitations only apply to orchestration functions and you can do all the aforementioned stuff in activity functions and as a matter of a fact that is exactly what you should do
Next I would like us to take a look at a bit more interesting pattern called Fan-out, Fan-in
Let’s imagine we are building a backup task for all files in a given folder
Files will be uploaded recursively to blob storage and the total number of bytes uploaded is counted during the process
A naive way to implement this would be to write a single function to take care of everything but the main problem with that would be scalability
A single function can only run in a single VM so you are limited to the throughput of that single VM
The other problem is that if there is a failure midway or the exection lasts longer than 10 minutes the backup will fail in partial state and the whole process has to be restarted
A better approach would be to write two functions: One which enumerates the files and adds the filenames to a queue and one that reads from the queue and uploads the files to storage
This would introduce a lot more complexity especially in the part where you want to provide the total amount of bytes uploaded, which would be the fanning back in part
Durable Functions makes implementing this relatively easy
Here is just the orchestrator function part of our backup example, The activity functions are not reallly interesting so I left them out
Here is the code that does the fanning out by calling CallFunctionAsync to get a task for each file
Then the fanning back in is achieved simply by calling Task.WhenAll on all the tasks which makes the code wait until all the tasks are done
After that the total number of bytes is calculated from the sum of the results of the tasks
Also what happens behind the covers is that checkpoints are created for each upload so that it is easy to resume the backup in case of for example network failure
This is a really powerful pattern and easy to implement with Durable Functions
Next I would like us to take a look at a very different kind of pattern, the Stateful Singleton
Most orchestrator functions have an explicit start and end and don’t directly interact with external event sources but Stateful Singleton is different
Stateful Singletons are also know as lightweight actors and though Durable Functions is not a proper implementation of the Actor Model but it has some of the same characteristics
Orchestrator functions are long-running, stateful, reliable, single-threaded, location transparent and globally addressable
This allows orchestrator functions to be used in actor-like situations
Here is all the code for a Stateful Singleton that acts as a counter
The function listens to an external event and then either increments or decrements the value in it’s state
After handling an event the function will continue waiting for new events until it is being given the end event
Here where we call the WaitForExternalEvent method, the actual waiting for the event is done
And here is the line that makes this orchestration long-running, because calling ContinueAsNew method makes it continue from the beginning
What the ContinueAsNew also does is that it resets the execution history to make sure the orchestration process will not run out of memory as the execution progresses
The last pattern I would like us to look at is the Human Interaction pattern
Often in processes we need some kind of human envolvement
What is tricky about humans is that they are a not always responsive or available
This requires implementing timeouts and and other strategies
And this time instead of just showing you the code I would like to actually show you a locally running two-factor authentication demo made with Durable Functions
By now hopefully if I’ve been at all successful atleast some of you are excited about Durable Functions and are anxious to get to test it yourselves
I have to give you a couple of words of caution though
First of all Durable Functions is still in a very early preview, what it means that stuff will change rapidly and if you are going to use this in production then stuff will break
Also right now and for the fore-seeable future orchestrator functions can only be written in C#, activity functions can be written in any language but return values only work in C#
And lastly you need the full Visual Studio 2017 with the Azure Functions tooling to be able to run Durable Functions locally
So you cannot run these locally with a Mac yet
But if these things wont scare you then I suggest you go check out Durable Functions as soon as possible and test them out yourselves
The documentation is actually quite good for an alpha release and there are downloadable examples of the different patterns and good installation notes for getting started
So that’s all for me, thank you for listening!
If you have questions go ahead and ask them or if were running out of time you can come see me afterwards I will be hanging out here for a while
Thanks!