Slide 1

Slide 1 text

Order from Chaos Building Serverless Workflows with Durable Functions @mark_heath https://markheath.net

Slide 2

Slide 2 text

@mark_heath Video uploaded Virus Scan File copy Extract metadata Database Audit Transcode Thumbnail Analytics Voice detection Notification icons designed by Smashicons from flaticons

Slide 3

Slide 3 text

“Functions as a Service” (FaaS) A managed platform that runs your code (a function) in response to an event (trigger) @mark_heath

Slide 4

Slide 4 text

Blob Cosmos DB HTTP Request Timer Queue Azure Functions Triggers @mark_heath

Slide 5

Slide 5 text

Serverless @mark_heath Managed Servers Automatic Scale Per-Second Billing icons designed by Smashicons from flaticons

Slide 6

Slide 6 text

Can we build serverless workflows with Azure Functions? @mark_heath

Slide 7

Slide 7 text

@mark_heath Function chaining with queues Video uploaded Extract Metadata Virus Scan File Copy

Slide 8

Slide 8 text

@mark_heath

Slide 9

Slide 9 text

@mark_heath

Slide 10

Slide 10 text

@mark_heath Video uploaded Virus Scan File copy Extract metadata Database Audit Transcode Thumbnail Analytics Voice detection Notification icons designed by Smashicons from flaticons Can’t see the big picture?

Slide 11

Slide 11 text

Image from The Art of Rube Goldberg: (A) Inventive (B) Cartoon (C) Genius, Selected and with commentary by Jennifer George; Introduction by Adam Gopnik, Published by Abrams ComicArts.

Slide 12

Slide 12 text

@mark_heath Video uploaded Virus Scan File copy Extract metadata Database Audit Transcode Thumbnail Analytics Voice detection Notification icons designed by Smashicons from flaticons Retries and backoff

Slide 13

Slide 13 text

@mark_heath Video uploaded Virus Scan File copy Extract metadata Database Audit Transcode Thumbnail Analytics Voice detection Notification icons designed by Smashicons from flaticons Error Handling Stuck Workflows

Slide 14

Slide 14 text

@mark_heath Video uploaded Virus Scan File copy Extract metadata Database Audit Transcode Thumbnail Analytics Voice detection Notification icons designed by Smashicons from flaticons Waiting for external events

Slide 15

Slide 15 text

Fan-out Fan-in Workflow @mark_heath easy! difficult!

Slide 16

Slide 16 text

Durable Functions to the rescue! @mark_heath

Slide 17

Slide 17 text

Durable Functions • An extension to Azure Functions • Microsoft.Azure.WebJobs.Extensions.DurableTask NuGet package • C# supported, JavaScript in preview • Open source • https://github.com/Azure/azure-functions-durable-extension @mark_heath

Slide 18

Slide 18 text

Orchestrator Functions • Define the steps in the workflow • Shows the big picture • Calls “activity functions” • Or other orchestrators (“sub-orchestrations”) • Decides what to do next • Handle exceptions across all activities • Must adhere to strict rules @mark_heath

Slide 19

Slide 19 text

Activity Functions • Perform steps in the workflow • Can receive input data and return output data • Can use “bindings” to connect to external services • (Just like a regular Azure Function) @mark_heath

Slide 20

Slide 20 text

Task Hubs • Stores state associated with workflows • Uses an Azure Storage account behind the scenes • (Tables and Queues) • Uses an event sourcing technique @mark_heath

Slide 21

Slide 21 text

REST API • Query orchestration status (GET) • https://{yourapp}.azurewebsites.net/runtime/webhooks/durabletask/ instances/{orchestration_id}?taskHub=DurableFunctionsHub& connection=Storage&code={code} • Send an event to an orchestration (POST) • https://{yourapp}.azurewebsites.net/runtime/webhooks/durabletask/ instances/{orchestration_id}/raiseEvent/{eventName}? taskHub=DurableFunctionsHub&connection=Storage&code={code} • Terminate an orchestration (POST) • https://{yourapp}.azurewebsites.net/runtime/webhooks/durabletask/ instances/{orchestration_id}/terminate?reason={text}& taskHub=DurableFunctionsHub&connection=Storage&code={code}

Slide 22

Slide 22 text

Demo Time! @mark_heath https://github.com/markheath/durable-functions-ecommerce-sample

Slide 23

Slide 23 text

@mark_heath Payment received Database Generate PDF Await approval Email customer Generate Video

Slide 24

Slide 24 text

[FunctionName("NewPurchaseWebhook")] public static async Task Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, [OrchestrationClient] DurableOrchestrationClient client) { string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var order = JsonConvert.DeserializeObject(requestBody); var orchestrationId = await client.StartNewAsync("O_ProcessOrder", order); return new OkResult(); } Starter Function @mark_heath

Slide 25

Slide 25 text

Orchestrator V1 [FunctionName("O_ProcessOrder")] public static async Task ProcessOrder( [OrchestrationTrigger] DurableOrchestrationContext ctx) { var order = ctx.GetInput(); await ctx.CallActivityAsync("A_SaveOrderToDatabase", order); var pdfLocation = await ctx.CallActivityAsync("A_CreatePersonalizedPdf", order); var videoLocation = await ctx.CallActivityAsync("A_CreateWatermarkedVideo", order); await ctx.CallActivityAsync("A_SendEmail", (order, pdfLocation, videoLocation)); return "Order processed successfully"; } @mark_heath

Slide 26

Slide 26 text

Activity Function [FunctionName("A_CreatePersonalizedPdf")] public static string CreatePersonalizedPdf( [ActivityTrigger] Order order, TraceWriter log) { log.Info("Creating PDF"); return $"{order.Id}.pdf"; } @mark_heath

Slide 27

Slide 27 text

Orchestrator V2 – Parallel Tasks var pdfTask = ctx.CallActivityAsync("A_CreatePersonalizedPdf", order); var videoTask = ctx.CallActivityAsync("A_CreateWatermarkedVideo", order); await Task.WhenAll(pdfTask, videoTask); var pdfLocation = pdfTask.Result; var videoLocation = videoTask.Result; @mark_heath

Slide 28

Slide 28 text

Exception Handling and Retry try { await ctx.CallActivityAsync ("A_CreatePersonalizedPdf", order); await ctx.CallActivityWithRetryAsync ("A_CreateWatermarkedVideo", new RetryOptions(TimeSpan.FromSeconds(30), 3), order); } catch (Exception ex) { log.Error($"Problem creating media files", ex); } @mark_heath

Slide 29

Slide 29 text

Waiting for External Events var approvalResult = await ctx.WaitForExternalEvent( "OrderApprovalResult", TimeSpan.FromMinutes(30), "TimedOut"); if (approvalResult == "TimedOut" || approvalResult == "Rejected") { await ctx.CallActivityAsync("A_OrderNotApproved", order); } else { // order was approved await ctx.CallActivityAsync("A_EmailCustomer", order); } @mark_heath

Slide 30

Slide 30 text

Sending an External Event [FunctionName("ApproveOrder")] public static async Task ApproveOrder( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, [OrchestrationClient] DurableOrchestrationClient client) { string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var approvalResult = JsonConvert.DeserializeObject(requestBody); await client.RaiseEventAsync(approvalResult.OrchestrationId, "OrderApprovalResult", approvalResult); return new OkResult(); } @mark_heath

Slide 31

Slide 31 text

Why Durable Functions? • Define the big picture in code • Handle errors for the workflow as a whole • Retry individual steps with back-off • Easily implement waiting for external events with timeout • Easily implement fan-out fan-in patterns • Track progress of workflows • Cancel workflows • It’s free and open source @mark_heath

Slide 32

Slide 32 text

@mark_heath

Slide 33

Slide 33 text

https://github.com/markheath/ durable-functions-ecommerce-sample https://markheath.net @mark_heath https://skillsmatter.com/conferences/ 10107-prognet-london-2018#skillscasts