love with Azure, and Xamarin.Forms • Developing distributed cloud systems with serverless for over 2.5 years • Spent the last 1.5+ years migrating, and developing serverless stuff on a cool & quirky SaaS project • Tested, and sometimes deployed, a whole lot of scenarios that probably weren’t intended to be ran on serverless ☺
Serverless != FaaS (Functions as a Service) • Serverless is great WHEN you really need it • Serverless is MORE expensive when you have a constant load • Breaking down your monolith into functions is hard, and might even slow down your system if you do it wrong • Functions enable you to shoot yourself in the foot without any proper tool to warn you about it
class Class1 { public static void Method1() { } } Second step • public static class Class1 { public static void Method1() { //Do some stuff Method2(); } public static void Method2() { //Do some stuff } }
Class1 { public static void Method1() { //Do some stuff Class2.Method2(); } } public static class Class2 { public static void Method2() { //Do some stuff } } Fourth step • public static class Class1 { public static void Method1() { //Do some stuff Class2.Method2(); } } public static class Class2 { public static void Method2() { //Do some stuff Class3.TriggerUpdateOneUI(); Class4.TriggerAnotherUpdate (); } }
Class1 { public static void Method1() { //Do some stuff Class2.Method2(); } } public static class Class2 { public static void Method2() { //Do some stuff Class3.TriggerUpdateOneUI(); Class4.TriggerAnotherUpdate (); } } Fifth step • public static class Class1 { public static void Method1() { //Do some stuff Class2.Method2(); } } public static class Class2 { public static void Method2() { //Do some stuff MessagingCenter.Send("done"); } }
clean, and it’s outside of the methods scope • The caller of your method might timeout because a method down the chain is taking too long • Hard to see the workflow without manual inspection / some cool tools in your IDE • Implementing a change is an adventure
class Class1 { public static void Method1() { //Do some stuff Class2.Method2(); } } public static class Class2 { public static void Method2() { //Do some stuff MessagingCenter.Send("done"); } } Sixth step • public static class Main { public static void HandleProcess1() { Class1.Method1(); Class2.Method2(); } } public static class Class1 { public static void Method1() { //Do some stuff } }
public static class Main { public static void HandleProcess1() { Class1.Method1(); Class2.Method2(); } } public static class Class1 { public static void Method1() { //Do some stuff } } Seventh step • public static class Main { public static async void HandleProcess() { await Class1.Method1(); await Class2.Method2(); } } public static class Class1 { public static async Task Method1() { //Do some stuff } }
We start using queues ☺ • But... We could benefit from using queues that support „transactions”, so that we can return something • That’s one of the reasons we should choose Service Bus Queues over Storage Queues • The challenge of getting data back depends on the type of infrastructure on which the „orchestrator” runs
concepts and features) Azure Event Grid • low latency • capable of receiving and processing millions of events per second • at least once delivery Azure Service Bus • reliable asynchronous message delivery (enterprise messaging as a service) that requires polling • advanced messaging features like FIFO, batching/sessions, transactions, dead-lettering, temporal control, routing and filtering, and duplicate detection • at least once delivery • optional in-order delivery
you won’t benefit from the values that get returned ☺ • Whenever a calling method „returns” you might need the context/results from the previous methods • Something might crash and you might need to resume/restart the process
Main { public static async void HandleProcess() { await Class1.Method1(); await Class2.Method2(); } } public static class Class1 { public static async Task Method1() { //Do some stuff } } Eight step • public static class Main { public static async void HandleProcess() { var a = await Class1.Method1(); var b = await Class2.Method2(); var c = await Class3.Method3(a); } } public static class Class1 { public static async Task<int> Method1() { //Do some stuff and return an int } }
Introducing Azure Durable Functions • Framework built on top of Functions to enable long-running tasks • They automatically checkpoint their progress whenever the function awaits. • Local state is never lost if the process recycles or the VM reboots.
to call... well... other functions • You might do an HTTP(S) request to an external service, but you might not want to do it • You could easily trigger an event, or add a message to a queue, but how do you get the result back?
deal to fan-out something – you just send out a bunch of messages to a queue in the worst case • The challenge is awaiting all those parallel „pipelines” to finish, and collect their result
await all of them ☺ for (int i = 0; i < workBatch.Length; i++) { Task<int> task = ctx.CallFunctionAsync<int>("F2", workBatch[i]); parallelTasks.Add(task); } await Task.WhenAll(parallelTasks);