Azure Durable Functions: Making Serverless Last
Serverless can be a confusing name for event-driven computing because it focuses so much on what you don’t have to care about rather than what you can do. The name does serve as a reminder that serverless platforms don’t help manage state; and while it’s good practice to externalize state so that it doesn’t interact with the business logic of an application, all but the simplest applications have state that needs managing.
The new Durable Functions feature in Microsoft’s own serverless service, Azure Functions, is one option for managing state, and Chris Anderson, senior program manager for Azure Functions, told the New Stack he hopes to see other frameworks and tools for helping with state so that can stay separate from the business logic. After all, being able to focus on that logic is the real advantage of serverless.
As well as taking away the burden of managing infrastructure, serverless also takes away existing tools for solving problems like state. “When we gave you just functions, we took away the lot of things you used to have like frameworks to manage state. This is like trying to create a web server without a framework like ASP.NET so you’re having to manage every part of the workflow of each request, only across many different services. Durable Functions is a first step towards doing more than just a point-to-point trigger.”
Durable Functions addresses the task of managing state for an application. “What customers had to do before was manage all that external state themselves, by messages along on a queue and having a record in a database somewhere with the details of the job, which can be large amounts of data. The queue itself can’t hold a whole lot of data; it can only hold a pointer to a place where this is more data.”
Durable Functions are intended to address a variety of patterns and scenarios that would quickly get complicated using triggers, timers and notifications, especially when orchestrating a range of activities with a complex set of tasks that need to happen each time a particular event occurs.
The simplest case is a “straight line” of events. “When I have one task, that causes another task to occur, that causes another task to occur, that causes another task to occur… with some if statements and other business logic to fork the workflow, but I’m trying to go from point a to point b,” Anderson explained.
Fan-out and fan-in is another common serverless pattern. Think of how MapReduce works. “Fanning out work to many parallel nodes works great in serverless because you’ve got lots of tiny machines; so if you’ve got a big work item, you want to split it up into as many small nodes as possible and fan out, and serverless will keep on fanning out as much in parallel as you need to and then scale back in. Whether you have one big job or lots of big jobs, it right sizes itself so you can always reach maximum values of parallelism,” Anderson said.
The part that’s always hard is the “fan in” step, Anderson said, because the workflow needs to know when all those messages have completed, so it can go run the next step of the process. Durable Functions allows the developer to express that with a simple a FOR loop and an AWAIT call to wait for all those things fanned out to complete.
“What used to be lots of complex pieces like polling and error cases and so on can all now be expressed in five lines of C#,” Anderson boasted. And don’t think of that just for data parallel operations; it’s also useful for automation, like provisioning multiple VMs in parallel, with multiple steps that have to complete, including having someone sign off on the process.
Durable Functions can keep track of state in looping processes, like a game show with multiple rounds. “I can manipulate it to do things that create what I call durable stateful singletons, which is orchestration that runs in a loop that keeps track of the current state of that object, and I can send it external messages to make it do other things.”
Another complex scenario Durable Functions can help with is waiting for some external interaction. “In the real world, we’re going to have other external systems that interact with our orchestrations; I can always try to wrap those things up in other functions but I don’t want to have a function that’s polling some external service to know whether it’s there or not,” Anderson said.
Durable Functions supports the idea of an external event, whether that’s another service or another function elsewhere, calling into the durable functions to pass it along with a piece of information and Durable Functions can wait on that event.
State Needn’t Be Expensive
Anderson suggested that would be a good way to handle user interactions with something driven by functions, like a two-factor authentication (2FA) service. “Humans don’t operate at the same speed as restful services! It’s going to take a few seconds to take out the phone to see what the 2FA code is.”
The Durable Functions orchestration can send the notification to the user that there’s a 2FA code to input, wait for the code to come back from the user, validate it or allow two or three more attempts before killing the login attempt, all without keeping the function running — and charging you for it.
“You don’t have long running functions waiting for other things to complete; as soon as it has to make an external call to get state, Durable Functions shuts down the orchestrator and you don’t pay for it anymore — so you only pay for the orchestrator when it’s not waiting around for external state.”
Durable Functions is obviously a good match for Azure services like Event Grid and Event Hubs, but it works well with third-party events too. Anderson mentioned using Twilio and a webhook request to Functions to add 2FA to Slack without needing to pull out a phone.
“Under the covers, it’s an HTTP request. You can have another function that acts as the front end for that external event, or the external event can call the admin endpoint directly,” Anderson said. “In practice, you generally have a function sitting in front and you can then have a couple of different triggers, like a queue or an admin panel with an HTTP endpoint and they can both trigger the function depending on which workflow makes sense.”
Azure Logic Apps workflows have been the main option for orchestration so far (and Durable Functions can run alongside Logic Apps), but that hasn’t suited developers who prefer to write code than use a graphical interface.
Although Azure Functions has a persistent file system behind the functions, rather than the usual read-only copy (because it was built upon Azure App Service and WebJobs), but that’s not a good place to store state because it’s so expensive. Instead, Durable Functions uses Azure storage queues and Azure table storage for key-value pairs. “Eventually we’ll give you options of using other underlying Azure technologies for higher performance,” Anderson said.
“We hope to have additional providers that let you move onto using Azure Service Bus queues and Cosmos DB for the higher throughput scenarios. Usually, you have to use something like Kafka or Event Hubs to manage that kind of throughput,” Anderson said.
Theoretically, that abstraction could make it possible for Durable Functions to work locally (as the Functions runtime already can). Whether that happens will depend on customer feedback, but Anderson talked hypothetically about being able to use Redis, for example, as the storage for Durable Functions.
Currently in preview, Durable Functions is likely to move to general availability with version 2 of Azure Functions (which it depends on). As well as the planned expansion of storage options and broader language support, it will add more scaling options in time. “We plan on doing auto-sharding for you, so you can take advantage of many instances and get parallel scale through that.”
But rather than expanding the scope of Durable Functions, Anderson hopes to see more frameworks and projects aimed at making it easier to do large-scale development with serverless.
“We had to make this tradeoff [with serverless]: you don’t have to manage infrastructure, but you do have to give up a lot more control over your application pipeline, and there are not many frameworks — if any — that work when limited down to a single function entry point. My expectation is that we’ll see a new generation of frameworks that operate at the single functions level,” Anderson said.
Microsoft is a sponsor of The New Stack.
Feature image via PXhere.