{"id":20635,"date":"2018-09-05T09:00:03","date_gmt":"2018-09-05T16:00:03","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/dotnet\/?p=19045"},"modified":"2022-06-10T11:42:37","modified_gmt":"2022-06-10T18:42:37","slug":"introduction-to-azure-durable-functions","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/introduction-to-azure-durable-functions\/","title":{"rendered":"Introduction to Azure Durable Functions"},"content":{"rendered":"<p class=\"code-line\">Azure Durable Functions is a new programming model based on Microsoft serverless&#8217; platform Azure Functions. It allows you to write a workflow as code and have the execution run with the scalability and the reliability of serverless with high throughput.<\/p>\n<h2 id=\"scenario\" class=\"code-line\">Scenario<\/h2>\n<p class=\"code-line\">Initially, I wanted to index data from GitHub repositories. I explained it all in a\u00a0<a title=\"https:\/\/blogs.msdn.microsoft.com\/appserviceteam\/2018\/08\/06\/learn-how-to-orchestrate-serverless-functions-by-scraping-apis-in-8-minutes\/?WT.mc_id=dotnet-blog-marouill\" href=\"https:\/\/blogs.msdn.microsoft.com\/appserviceteam\/2018\/08\/06\/learn-how-to-orchestrate-serverless-functions-by-scraping-apis-in-8-minutes\/?WT.mc_id=dotnet-blog-marouill\">previous post<\/a>, but I&#8217;ll drill down into the concepts today.<\/p>\n<p class=\"code-line\">To summarize the post, I wanted to retrieve a list of repositories that I wanted to index. Then, query each repository for more detailed information. Finally, save the data into a database.<\/p>\n<p class=\"code-line\">Today, we&#8217;ll do something similar but to keep things simple, I&#8217;ll save the content to Azure Blob Storage.<\/p>\n<p class=\"code-line\">If you want to follow along, I&#8217;ve created\u00a0<a title=\"https:\/\/aka.ms\/DurableFunctionsSample\" href=\"https:\/\/aka.ms\/DurableFunctionsSample\">a sample<\/a>\u00a0that contains all the code in this post.<\/p>\n<p class=\"code-line\">Let&#8217;s get started.<\/p>\n<h2 id=\"concepts\" class=\"code-line\">Concepts<\/h2>\n<p class=\"code-line code-active-line\">Besides the common\u00a0<a title=\"https:\/\/docs.microsoft.com\/dotnet\/standard\/serverless-architecture\/?WT.mc_id=dotnet-blog-marouill\" href=\"https:\/\/docs.microsoft.com\/dotnet\/standard\/serverless-architecture\/?WT.mc_id=dotnet-blog-marouill\">serverless concepts<\/a>, Azure Durable Functions introduces more concepts that make developing complex workflow easy.<\/p>\n<p class=\"code-line\">Let&#8217;s start with the basic concepts and work our way up.<\/p>\n<h3 id=\"definition-of-a-function\" class=\"code-line\">Definition of a Function<\/h3>\n<p class=\"code-line\">A serverless function on Azure is a unit of work that is, in C#, a single method from a static class. Azure Functions allows you only pay for what you use as well as scaling that piece of code for you.<\/p>\n<p class=\"code-line\">Generous\u00a0<a title=\"https:\/\/azure.microsoft.com\/pricing\/details\/functions\/?WT.mc_id=dotnet-blog-marouill\" href=\"https:\/\/azure.microsoft.com\/pricing\/details\/functions\/?WT.mc_id=dotnet-blog-marouill\">free quotas<\/a>\u00a0are also given to allow you to experiment quickly and cheaply in the cloud.<\/p>\n<p class=\"code-line\">In C#, we can write a simple Function with the following code.<\/p>\n<pre><code class=\"csharp\">public static class MyFunction\r\n{\r\n    [FunctionName(\"MyFirstFunction\")]\r\n    public void MyFirstFunction()\r\n    {\r\n        \/\/...\r\n    }\r\n}<\/code><\/pre>\n<h3 id=\"definition-of-a-trigger\" class=\"code-line\">Definition of a trigger<\/h3>\n<p class=\"code-line\">A trigger is an event happening to which a piece of code responds.<\/p>\n<p class=\"code-line\">It is part of what is called a\u00a0<em>binding<\/em>\u00a0which hooks a method, a variable, or a parameter of your code to external systems.<\/p>\n<p class=\"code-line\">Bindings come in 3 types, but we&#8217;re only interested in the latter. For more information on bindings, you can read the\u00a0<a title=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/functions-triggers-bindings?WT.mc_id=dotnet-blog-marouill\" href=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/functions-triggers-bindings?WT.mc_id=dotnet-blog-marouill\">concept page<\/a><\/p>\n<ul>\n<li class=\"code-line\">Input<\/li>\n<li class=\"code-line\">Output<\/li>\n<li class=\"code-line\">Trigger<\/li>\n<\/ul>\n<p class=\"code-line\">By looking at the list of\u00a0<a title=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/functions-triggers-bindings?WT.mc_id=dotnet-blog-marouill#supported-bindings\" href=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/functions-triggers-bindings?WT.mc_id=dotnet-blog-marouill#supported-bindings\">supported bindings<\/a>, we see a\u00a0<code>Trigger<\/code>\u00a0column. Triggers include storage events (Blob Storage, Cosmos DB, or other.) as well as eventing systems such as Event Grid and Event Hubs.<\/p>\n<p class=\"code-line\">The most common triggers, however, are\u00a0<code>Http<\/code>, which respond to an HTTP request from a user, as well as\u00a0<code>Timer<\/code>\u00a0which allows you to specific code on a specified schedule.<\/p>\n<p class=\"code-line code-active-line\">Those triggers are applied directly on a parameter of a function.<\/p>\n<pre><code class=\"csharp\">public static class MyFunction\r\n{\r\n    \/\/ The timer trigger is based on a CRON expression.\r\n    \/\/ {second} {minute} {hour} {day} {month} {day-of-week}\r\n    \/\/ In this case, the timer is every 5 minutes.\r\n    [FunctionName(\"MyTimerTrigger\")]\r\n    public static void MyTimerTrigger([TimerTrigger(\"0 *\/5 * * * *\")]TimerInfo myTimer) { \/* ... *\/ }\r\n\r\n    [FunctionName(\"HttpTriggerCSharp\")]\r\n    public static async Task Run(\r\n        [HttpTrigger(AuthorizationLevel.Function, \"get\", \"post\", Route = null)]HttpRequestMessage req) { \/* ... *\/}\r\n}<\/code><\/pre>\n<p class=\"code-line\">Those are traditional functions that you find in a serverless application deployed on Azure. They are simple and respond to events.<\/p>\n<p class=\"code-line\">What if you need something more complicated? What about calling functions with functions? For example, invoking one function for every element of a list then reconciling the result and saving it to a file.<\/p>\n<p class=\"code-line\">Writing a complex workflow with simple code is where Durable Functions comes in.<\/p>\n<h3 id=\"definition-of-an-orchestrator-function\" class=\"code-line\">Definition of an Orchestrator Function<\/h3>\n<p class=\"code-line\">An Orchestrator is an Azure Function with specific behaviors attached to them. As an example, it automatically set checkpoint during its execution, shut itself down while waiting for other functions to finish executing, then replay through the checkpoint to resume execution.<\/p>\n<p class=\"code-line\">They are at the very heart of how Durable Functions works.<\/p>\n<p class=\"code-line\">It is important to remember how an Orchestrator function operates differently than a standard function. While a normal function only executes once per event, the orchestrator is restarted many times while waiting for other functions to complete.<\/p>\n<p class=\"code-line\">This kind of behavior means that this function needs to be\u00a0<em>deterministic<\/em>. It must return the same result each time. It is crucial then to not use\u00a0<code>DateTime.Now<\/code>,\u00a0<code>Guid.NewGuid()<\/code>\u00a0or anything generating a different result in this method.\u00a0<a title=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/durable-functions-checkpointing-and-replay?WT.mc_id=dotnet-blog-marouill\" href=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/durable-functions-checkpointing-and-replay?WT.mc_id=dotnet-blog-marouill\">More information is available on the checkpoint and replay pattern that Orchestrators are using internally<\/a>.<\/p>\n<p class=\"code-line\">An Orchestrator function is a function with an\u00a0<code>OrchestrationTrigger<\/code>\u00a0on a\u00a0<code>DurableOrchestrationContext<\/code>\u00a0object parameter.<\/p>\n<pre><code class=\"csharp\">[FunctionName(\"Orchestrator\")]\r\npublic static async Task RunOrchestrator([OrchestrationTrigger] DurableOrchestrationContext context)\r\n{\r\n    return context.InstanceId;\r\n}<\/code><\/pre>\n<p>It is invoked by a\u00a0<code>DurableOrchestrationClient<\/code>\u00a0decorated with an\u00a0<code>OrchestrationClientAttribute<\/code>\u00a0injected within an ordinary function with any triggers. Let&#8217;s take a\u00a0<code>Timer<\/code>\u00a0trigger as an example.<\/p>\n<pre><code class=\"csharp\">[FunctionName(\"MyTimerTrigger\")]\r\npublic static void MyTimerTrigger([TimerTrigger(\"0 *\/5 * * * *\")]TimerInfo myTimer, [OrchestrationClient]DurableOrchestrationClient starter)\r\n{\r\n    \/\/ Function input comes from the request content.\r\n    string instanceId = await starter.StartNewAsync(\"Orchestrator\", null);\r\n    \/* ... *\/\r\n}<\/code><\/pre>\n<p class=\"code-line\">At this point, we have an orchestrator that is ready to run other functions.<\/p>\n<h3 id=\"definition-of-an-activity-function\" class=\"code-line\">Definition of an Activity Function<\/h3>\n<p class=\"code-line\">Not every function can be used with an orchestrator. Those functions become an Activity Function when an\u00a0<code>ActivityTriggerAttribute<\/code>\u00a0is on a\u00a0<code>DurableActivityContext<\/code>\u00a0parameter.<\/p>\n<pre><code class=\"csharp\">[FunctionName(\"MyActivity\")]\r\npublic static async Task MyActivity([ActivityTrigger] DurableActivityContext context)\r\n{\r\n    \/* ... *\/\r\n}<\/code><\/pre>\n<p class=\"code-line\">Activities are part of the checkpoint and replay pattern described previously. Among the differences with other functions, they do not respond to other triggers than an orchestrator calling them.<\/p>\n<p class=\"code-line\">An activity is a perfect place to have code accessing a database, sending emails, or any other external systems. Activities that have been called and returned have their results cached. Meaning, that returning 1000 rows from a database won&#8217;t be done multiple times but only a single time.<\/p>\n<p class=\"code-line\">As an example, our sample uses an activity function to retrieve the list of repositories from which we want to extract more data.<\/p>\n<pre><code class=\"csharp\">[FunctionName(\"GetAllRepositoriesForOrganization\")]\r\npublic static async Task&lt;List&gt; GetAllRepositoriesForOrganization([ActivityTrigger] DurableActivityContext context)\r\n{\r\n    \/\/ retrieves the organization name from the Orchestrator function\r\n    var organizationName = context.GetInput();\r\n    \/\/ invoke the API to retrieve the list of repositories of a specific organization\r\n    var repositories = (await github.Repository.GetAllForOrg(organizationName)).Select(x =&gt; (x.Id, x.Name)).ToList();\r\n    return repositories;\r\n}<\/code><\/pre>\n<p class=\"code-line\">An Activity Function is not re-executed for the same Orchestrator instance. In this scenario, we preserve the list of repositories without invoking the API again.<\/p>\n<p class=\"code-line\">This caching mechanism gives us significant leverage while orchestrating complex workflows. First, it allows us to keep the list of data on which we operate fixed. Second, since the orchestrator may call that function multiple times, it&#8217;s essential to have the result cached to avoid crashing external systems. Finally, it becomes possible to debug what we send\/return to activities since every execution is logged transactionally by the Durable Functions component.<\/p>\n<h3 id=\"code-as-orchestration\" class=\"code-line\">Code as orchestration<\/h3>\n<p class=\"code-line\">With those concepts clarified, let&#8217;s look at Code as Orchestration.<\/p>\n<p class=\"code-line\">Workflows in the past were traditionally built with either a graphic designer or data persistence format (XML, JSON, YAML, or other). Those are easy to create and understand for small workflow. However, they become tough to debug and understand where a failure occurs.<\/p>\n<p class=\"code-line\">On top of that, they were never meant to run on a high scale infrastructure where one part of the workflow would need to be scale differently.<\/p>\n<p class=\"code-line\">Let&#8217;s take a simple example.<\/p>\n<blockquote class=\"code-line\">\n<p class=\"code-line\">I want to retrieve the list of opened issues for all repositories within a GitHub organization and save the count somewhere in the cloud.<\/p>\n<\/blockquote>\n<p class=\"code-line\">Here&#8217;s how it looks in pseudo-code.<\/p>\n<pre><code class=\"nohighlight\">repositories = getAllRepositories(organizationName);\r\nforeach( repository in repositories)\r\n    repository.getOpenedIssuesCount()\r\ncloud.save(repository)<\/code><\/pre>\n<p class=\"code-line\">Here&#8217;s how you would represent it with Azure Durable Functions.<\/p>\n<p class=\"code-line code-active-line\">It is the same code found in\u00a0<a title=\"https:\/\/aka.ms\/DurableFunctionsSample\" href=\"https:\/\/aka.ms\/DurableFunctionsSample\">the sample<\/a>\u00a0on GitHub.<\/p>\n<pre><code class=\"csharp\">[FunctionName(\"Orchestrator\")]\r\npublic static async Task RunOrchestrator(\r\n    [OrchestrationTrigger] DurableOrchestrationContext context)\r\n{\r\n    \/\/ retrieves the organization name from the Orchestrator_HttpStart function\r\n    var organizationName = context.GetInput();\r\n    \/\/ retrieves the list of repositories for an organization by invoking a separate Activity Function.\r\n    var repositories = await context.CallActivityAsync&lt;List&gt;(\"GetAllRepositoriesForOrganization\", organizationName);\r\n\r\n    \/\/ Creates an array of task to store the result of each functions\r\n    var tasks = new Task[repositories.Count];\r\n    for (int i = 0; i &lt; repositories.Count; i++)\r\n    {\r\n        \/\/ Starting a `GetOpenedIssues` activity WITHOUT `async`\r\n        \/\/ This will starts Activity Functions in parallel instead of sequentially.\r\n        tasks[i] = context.CallActivityAsync(\"GetOpenedIssues\", (repositories[i]));\r\n    }\r\n\r\n    \/\/ Wait for all Activity Functions to complete execution\r\n    await Task.WhenAll(tasks);\r\n\r\n    \/\/ Retrieve the result of each Activity Function and return them in a list\r\n    var openedIssues = tasks.Select(x =&gt; x.Result).ToList();\r\n\r\n    \/\/ Send the list to an Activity Function to save them to Blob Storage.\r\n    await context.CallActivityAsync(\"SaveRepositories\", openedIssues);\r\n\r\n    return context.InstanceId;\r\n}<\/code><\/pre>\n<p class=\"code-line\">Let&#8217;s walk through this orchestrator line by line. I retrieve an organization name from the function that triggered the Orchestrator. The input mechanism allows me to reuse the code for more than a single purpose. Then, I invoke a function that returns me a list of all repositories.<\/p>\n<p class=\"code-line\">Once the list is returned, and not before, we invoke as many\u00a0<code>GetOpenedIssues<\/code>\u00a0functions as necessary to complete our task. Note that we are not using the\u00a0<code>await<\/code>\u00a0keyword here meaning that they are executing in parallel instead of sequentially.<\/p>\n<p class=\"code-line\">Finally, we wait for all the functions to complete their executions before sending the compiled results to a\u00a0<code>SaveRepositories<\/code>\u00a0function to save them to Blob Storage.<\/p>\n<p class=\"code-line\">With as few as 8 lines of codes, we managed to build a complex workflow without XML\/JSON that your team can understand quickly.<\/p>\n<p class=\"code-line\">Give it a try now by downloading\u00a0<a title=\"https:\/\/aka.ms\/DurableFunctionsSample\" href=\"https:\/\/aka.ms\/DurableFunctionsSample\">the sample<\/a>\u00a0and trying it out! If you want to run it in the cloud,\u00a0<a title=\"vscode-resource:\/c:\/git_ws\/MaximRouiller\/experimental_samples\/durable-function\/azure.microsoft.com\/free\/\" href=\"https:\/\/azure.microsoft.com\/free\/\">get a free Azure subscription<\/a>\u00a0and take advantage of free Azure Functions.<\/p>\n<h2 id=\"resources\" class=\"code-line\">Resources<\/h2>\n<p class=\"code-line\">To get more information on Azure Durable Functions here&#8217;s some reading material.<\/p>\n<ul>\n<li class=\"code-line\">EBook:\u00a0<a title=\"https:\/\/docs.microsoft.com\/dotnet\/standard\/serverless-architecture\/?WT.mc_id=dotnet-blog-marouill\" href=\"https:\/\/docs.microsoft.com\/dotnet\/standard\/serverless-architecture\/?WT.mc_id=dotnet-blog-marouill\">Serverless apps: Architecture, patterns and Azure implementation<\/a><\/li>\n<li class=\"code-line\"><a title=\"https:\/\/blogs.msdn.microsoft.com\/appserviceteam\/2018\/08\/06\/learn-how-to-orchestrate-serverless-functions-by-scraping-apis-in-8-minutes\/?WT.mc_id=dotnet-blog-marouill\" href=\"https:\/\/blogs.msdn.microsoft.com\/appserviceteam\/2018\/08\/06\/learn-how-to-orchestrate-serverless-functions-by-scraping-apis-in-8-minutes\/?WT.mc_id=dotnet-blog-marouill\">Learn how to orchestrate serverless function by scraping APIs in 8 minutes<\/a><\/li>\n<li class=\"code-line\"><a title=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/durable-functions-checkpointing-and-replay?WT.mc_id=dotnet-blog-marouill\" href=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/durable-functions-checkpointing-and-replay?WT.mc_id=dotnet-blog-marouill\">Durable Function Orchestrator Checkpoint and replay<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Azure Durable Functions is a new programming model based on Microsoft serverless&#8217; platform Azure Functions. It allows you to write a workflow as code and have the execution run with the scalability and the reliability of serverless with high throughput. Scenario Initially, I wanted to index data from GitHub repositories. I explained it all in [&hellip;]<\/p>\n","protected":false},"author":41506,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685],"tags":[4,9,37],"class_list":["post-20635","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","tag-net","tag-net-core","tag-azure"],"acf":[],"blog_post_summary":"<p>Azure Durable Functions is a new programming model based on Microsoft serverless&#8217; platform Azure Functions. It allows you to write a workflow as code and have the execution run with the scalability and the reliability of serverless with high throughput. Scenario Initially, I wanted to index data from GitHub repositories. I explained it all in [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/20635","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/41506"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=20635"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/20635\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=20635"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=20635"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=20635"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}