Slide 1

Slide 1 text

Making the cloud event- driven, and orchestrated

Slide 2

Slide 2 text

Who am I? • Ivan Čuljak • .NET freelancer in 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 ☺

Slide 3

Slide 3 text

Code examples are oversimplified to fit on the slide  Disclamer #1

Slide 4

Slide 4 text

This talk is mostly about serverless problems Disclamer #2

Slide 5

Slide 5 text

You can apply the concepts and services „anywhere” Disclamer #3

Slide 6

Slide 6 text

First of all – let’s get something straight ☺ • 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

Slide 7

Slide 7 text

Let’s build a plain old „console” app (and draw parallels with cloud)

Slide 8

Slide 8 text

A really simple „console” app First step • public static 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 } }

Slide 9

Slide 9 text

After some change requests Third 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 } } 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 (); } }

Slide 10

Slide 10 text

Methods are handling stuff outside of their scope Problem #1

Slide 11

Slide 11 text

Why is this even a problem? • Spaghetti code <3 • It’s out of the methods scope • A crash or delay in the called method might set everything to fire • Extremely hard to maintain, and debug

Slide 12

Slide 12 text

Let’s introduce some messages 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 (); } } 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"); } }

Slide 13

Slide 13 text

How do we solve this problem in the cloud? • Introducing Azure Event Grid

Slide 14

Slide 14 text

Methods contain „business logic” irrelevant to them Problem #2

Slide 15

Slide 15 text

Why is this even a problem? • Your code isn’t 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

Slide 16

Slide 16 text

Let’s introduce a „function orchestrator” 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"); } } 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 } }

Slide 17

Slide 17 text

How do we solve this problem in the cloud? • We create yet another service/function/something that will group all the „business logic”

Slide 18

Slide 18 text

Orchestrator is waiting for all the other methods to finish Problem #3

Slide 19

Slide 19 text

Why is this even a problem? • It’s blocking some resources (a thread, an FaaS instance, something...) • Those resources cost money... more noticeable on serverless than anywhere else

Slide 20

Slide 20 text

Let’s make them async and await them 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 } } 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 } }

Slide 21

Slide 21 text

How do we solve this problem in the cloud? • 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

Slide 22

Slide 22 text

Why are we mixing events and messages? (because of different 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

Slide 23

Slide 23 text

Where do you store your context/results? Problem #4

Slide 24

Slide 24 text

Why is this even a problem? • It’s not if 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

Slide 25

Slide 25 text

Let’s return some values 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 } } 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 Method1() { //Do some stuff and return an int } }

Slide 26

Slide 26 text

How do we solve this problem in the cloud? • 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.

Slide 27

Slide 27 text

Now, let’s completely move to the cloud (except for those on-prem machines doing resource intensive processing)

Slide 28

Slide 28 text

Let’s use something that’s not a function Challenge #1

Slide 29

Slide 29 text

Why is this a challenge? • Durable Functions are designed 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?

Slide 30

Slide 30 text

How do we tackle it in the cloud? Task approvalEvent = ctx.WaitForExternalEvent("ApprovalEvent"); • We send the request down the queue, and await for an external event

Slide 31

Slide 31 text

How do you fan-out, and especially fan-in? Challenge #2

Slide 32

Slide 32 text

Why is this a challenge? • It’s not a huge 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

Slide 33

Slide 33 text

How do we tackle it in the cloud? • We await all of them ☺ for (int i = 0; i < workBatch.Length; i++) { Task task = ctx.CallFunctionAsync("F2", workBatch[i]); parallelTasks.Add(task); } await Task.WhenAll(parallelTasks);

Slide 34

Slide 34 text

A hungry shark comes along and disconnects Ireland from the rest of the world

Slide 35

Slide 35 text

Durable Functions & Databases can handle it

Slide 36

Slide 36 text

Almost everything else needs additional services So... say hello to API Management

Slide 37

Slide 37 text

There’s so much left to say, but we’re out of time  Feel free to ping me if you’ll need me

Slide 38

Slide 38 text

Thank you <3 Any questions? @CuljakIvan [email protected]