6. @pacodelacruz
Serverless FaaS and its Benefits
Server abstraction
(Ops Productivity)
Scaling,
Load balancing &
High availability
built-in
7. @pacodelacruz
Serverless FaaS and its Benefits
Server abstraction
(Ops Productivity)
Event-driven scaling
not resource-driven
Scaling,
Load balancing &
High availability
built-in
Pay only for
what you use
Devs Productivity
(Programming
Models)
8. @pacodelacruz
Azure Functions in a Nutshell
Event Triggers Code Outputs
React and get inputs from
a growing list of services
(triggers and input
bindings)
C#, F#,
Node.js, Java,
Python, PowerShell
Send results to a
growing list of services
(output bindings)
9. @pacodelacruz
Durable Functions in a Nutshell
Based on
Durable Task Framework
Using Azure Storage
(Managed & Abstracted)
To Implement
stateful entities and
workflows-as-code
(C#, F# & Node.js)
Azure Functions
Extension
10. @pacodelacruz
Durable Entities (Actor-Like)
HTTP Calls from Orch. (with MI)
Pluggable State Providers
Testability Improvements
Orchestrator Roslyn Analyser
What’s Coming in Durable Functions 2.0
11. @pacodelacruz
Durable Functions Patterns (1.0)
Function Chaining Fan-out & Fan-in Async HTTP APIs
Human Interaction /
Wait for External Events
Monitoring
Start
Get Status
12. @pacodelacruz
Durable Functions Patterns (2.0)
Function Chaining Fan-out & Fan-in Async HTTP APIs
Human Interaction /
Wait for External Events
Monitoring Durable Entities *
Start
Get Status
Query
* New on 2.0
14. @pacodelacruz
Durable Functions Types (2.0)
Entity*Client ActivityOrchestrator
Start Orch.
Query Orch.
Terminate Orch.
Signal Orch.
Signal Entity*
Query Entity*
Call Activity
Call Sub-orch.
Set Status
Call Entity*
Perform Step,
IO
Initialise*
Destruct*
Handle Event*
Set State*
Stateless Stateful Stateless Stateful
Client Orchestrator Activity Entity*
* New on 2.0
15. @pacodelacruz
Addressable via entity Id
Operations execute serially
Created when called or signalled
When not executing, unloaded from memory
One-way messaging from Clients and other Entities ^
Two-way requests from Orchestrations ^
Orchestrations provide distributed locking ^
Durability over latency ^
Durable Entities (Actor-Like)
^ Different from virtual-actors
16. @pacodelacruz
Function Chaining Pattern
public static async Task<object> Run(
[OrchestrationTrigger] DurableOrchestrationContext ctx)
{
try
{
var x = await ctx.CallActivityAsync<object>("F1");
var y = await ctx.CallActivityAsync<object>("F2", x);
return await ctx.CallActivityAsync<object>("F3", y);
}
catch (Exception ex)
{
// error handling / compensation
}
}
17. @pacodelacruz
Function Chaining Pattern
public static async Task<object> Run(
[OrchestrationTrigger] DurableOrchestrationContext ctx)
{
try
{
var x = await ctx.CallActivityAsync<object>("F1");
var y = await ctx.CallActivityAsync<object>("F2", x);
return await ctx.CallActivityAsync<object>("F3", y);
}
catch (Exception ex)
{
// error handling / compensation
}
}
18. @pacodelacruz
Function Chaining Pattern
public static async Task<object> Run(
[OrchestrationTrigger] DurableOrchestrationContext ctx)
{
try
{
var x = await ctx.CallActivityAsync<object>("F1");
var y = await ctx.CallActivityAsync<object>("F2", x);
return await ctx.CallActivityAsync<object>("F3", y);
}
catch (Exception ex)
{
// error handling / compensation
}
}
19. @pacodelacruz
Fan-out & Fan-In Pattern
public static async Task<int> Run(
[OrchestrationTrigger] DurableOrchestrationContext ctx)
{
object[] workBatch = await ctx.CallActivityAsync<object[]>("F1");
var tasks = new Task<long>[workBatch.Length];
for (int i = 0; i < workBatch.Length; i++)
{
tasks[i] = ctx.CallActivityAsync<int>("F2", workBatch[i]);
}
await Task.WhenAll(tasks);
long sum = tasks.Sum(t => t.Result);
return sum;
}
20. @pacodelacruz
Fan-out & Fan-In Pattern
public static async Task<int> Run(
[OrchestrationTrigger] DurableOrchestrationContext ctx)
{
object[] workBatch = await ctx.CallActivityAsync<object[]>("F1");
var tasks = new Task<long>[workBatch.Length];
for (int i = 0; i < workBatch.Length; i++)
{
tasks[i] = ctx.CallActivityAsync<int>("F2", workBatch[i]);
}
await Task.WhenAll(tasks);
long sum = tasks.Sum(t => t.Result);
return sum;
}
CallActivityWithRetryAsync
21. @pacodelacruz
Orchestration Client
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, methods: "post",
Route = "orchestrators/{functionName}")] HttpRequestMessage req,
[OrchestrationClient] DurableOrchestrationClientBase starter, ILogger log)
{
// Function input comes from the request content.
dynamic eventData = await req.Content.ReadAsAsync<object>();
string instanceId = await starter.StartNewAsync("myOrchestrator", eventData);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
var res = starter.CreateCheckStatusResponse(req, instanceId);
return res;
}
22. @pacodelacruz
Orchestration Client
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, methods: "post",
Route = "orchestrators/{functionName}")] HttpRequestMessage req,
[OrchestrationClient] DurableOrchestrationClientBase starter, ILogger log)
{
// Function input comes from the request content.
dynamic eventData = await req.Content.ReadAsAsync<object>();
string instanceId = await starter.StartNewAsync("myOrchestrator", eventData);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
var res = starter.CreateCheckStatusResponse(req, instanceId);
return res;
}
23. @pacodelacruz
Orchestration Client
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, methods: "post",
Route = "orchestrators/{functionName}")] HttpRequestMessage req,
[OrchestrationClient] DurableOrchestrationClientBase starter, ILogger log)
{
// Function input comes from the request content.
dynamic eventData = await req.Content.ReadAsAsync<object>();
string instanceId = await starter.StartNewAsync("myOrchestrator", eventData);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
var res = starter.CreateCheckStatusResponse(req, instanceId);
return res;
}
24. @pacodelacruz
Durable Entity Functions
public class Counter
{
[JsonProperty("value")]
public int CurrentValue { get; set; }
public void Add(int amount) => this.CurrentValue += amount;
public void Reset() => this.CurrentValue = 0;
public int Get() => this.CurrentValue;
[FunctionName(nameof(Counter))]
public static Task Run([EntityTrigger] IDurableEntityContext ctx)
=> ctx.DispatchAsync<Counter>();
}
25. @pacodelacruz
Durable Entity Functions
public class Counter
{
[JsonProperty("value")]
public int CurrentValue { get; set; }
public void Add(int amount) => this.CurrentValue += amount;
public void Reset() => this.CurrentValue = 0;
public int Get() => this.CurrentValue;
[FunctionName(nameof(Counter))]
public static Task Run([EntityTrigger] IDurableEntityContext ctx)
=> ctx.DispatchAsync<Counter>();
}
26. @pacodelacruz
Durable Entity Functions
public class Counter
{
[JsonProperty("value")]
public int CurrentValue { get; set; }
public void Add(int amount) => this.CurrentValue += amount;
public void Reset() => this.CurrentValue = 0;
public int Get() => this.CurrentValue;
[FunctionName(nameof(Counter))]
public static Task Run([EntityTrigger] IDurableEntityContext ctx)
=> ctx.DispatchAsync<Counter>();
}
27. @pacodelacruz
Durable Entity Functions
public class Counter
{
[JsonProperty("value")]
public int CurrentValue { get; set; }
public void Add(int amount) => this.CurrentValue += amount;
public void Reset() => this.CurrentValue = 0;
public int Get() => this.CurrentValue;
[FunctionName(nameof(Counter))]
public static Task Run([EntityTrigger] IDurableEntityContext ctx)
=> ctx.DispatchAsync<Counter>();
}
28. @pacodelacruz
Durable Functions vs Logic Apps?
Durable Functions Logic Apps
Stateful workflows and entities Stateful workflows
C#, F# and JavaScript Visual designer and WDL
Bindings (~ 20 supported) 250+ connectors
Portable Runtime Run only on Azure
Monitoring based on App Insights & APIs Rich monitoring & management tools
Serverless, dedicated and isolated Serverless & dedicated (ISE)
platform.deloitte.com.au/articles/azure-durable-functions-vs-logic-apps
30. @pacodelacruz
Stateful Serverless Request Bin
Why Having Your Own Serverless Request Bin?
Deploy to Azure
Understand the Solution
Test It!
Demo
github.com/pacodelacruz/
serverless-request-bin-durable-functions