Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Help! I've created a serverless monolith! - NDC...

Marc Duiker
September 29, 2022

Help! I've created a serverless monolith! - NDC Oslo 2022

Slides of my session at NDC Oslo Sep 29th 2022.
https://twitter.com/marcduiker

Marc Duiker

September 29, 2022
Tweet

More Decks by Marc Duiker

Other Decks in Technology

Transcript

  1. @MarcDuiker 11 https://en.wikipedia.org/wiki/Modularity “…modularity is the degree to which a

    system's components may be separated and recombined, often with the benefit of flexibility and variety in use.”
  2. @MarcDuiker 19 https://martinfowler.com/articles/agileStory.html “We eventually agreed on "agile" as we

    felt that captured the adaptiveness and response to change which we felt was so important to our approach…”
  3. @MarcDuiker 38 Caused by the nature of the (business) problem.

    Can’t be easily reduced. Caused by decisions we make related to architecture, frameworks, packages, code style etc. Can be reduced. https://en.wikipedia.org/wiki/Programming_complexity
  4. @MarcDuiker 39 https://en.wikipedia.org/wiki/Programming_complexity Caused by decisions we make related to

    architecture, frameworks, packages, code style etc. Can be reduced. Caused by the nature of the (business) problem. Can’t be easily reduced.
  5. @MarcDuiker 49 public static class ChainingExample { [FunctionName(nameof(ChainingExample))] public static

    async Task<string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var resultA = await context.CallActivityAsync<string>( nameof(ActivityFunctionA), null); var resultB = await context.CallActivityAsync<string>( nameof(ActivityFunctionB), resultA); var resultC = await context.CallActivityAsync<string>( nameof(ActivityFunctionC), resultB); return resultC; } }
  6. @MarcDuiker 50 public static class ChainingExample { [FunctionName(nameof(ChainingExample))] public static

    async Task<string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var resultA = await context.CallActivityAsync<string>( nameof(ActivityFunctionA), null); var resultB = await context.CallActivityAsync<string>( nameof(ActivityFunctionB), resultA); var resultC = await context.CallActivityAsync<string>( nameof(ActivityFunctionC), resultB); return resultC; } }
  7. @MarcDuiker 51 public static class ChainingExample { [FunctionName(nameof(ChainingExample))] public static

    async Task<string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var resultA = await context.CallActivityAsync<string>( nameof(ActivityFunctionA), null); var resultB = await context.CallActivityAsync<string>( nameof(ActivityFunctionB), resultA); var resultC = await context.CallActivityAsync<string>( nameof(ActivityFunctionC), resultB); return resultC; } }
  8. @MarcDuiker 52 public static class ChainingExample { [FunctionName(nameof(ChainingExample))] public static

    async Task<string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var resultA = await context.CallActivityAsync<string>( nameof(ActivityFunctionA), null); var resultB = await context.CallActivityAsync<string>( nameof(ActivityFunctionB), resultA); var resultC = await context.CallActivityAsync<string>( nameof(ActivityFunctionC), resultB); return resultC; } }
  9. @MarcDuiker 53 public static class ChainingExample { [FunctionName(nameof(ChainingExample))] public static

    async Task<string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var resultA = await context.CallActivityAsync<string>( nameof(ActivityFunctionA), null); var resultB = await context.CallActivityAsync<string>( nameof(ActivityFunctionB), resultA); var resultC = await context.CallActivityAsync<string>( nameof(ActivityFunctionC), resultB); return resultC; } }
  10. @MarcDuiker 55 public static class FanOutFanInExample { [FunctionName(nameof(FanOutFanInExample))] public static

    async Task<string[]> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var tasks = new List<Task<string>>(); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionA), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionB), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionC), null)); var results = await Task.WhenAll(tasks); return results; }
  11. @MarcDuiker 56 public static class FanOutFanInExample { [FunctionName(nameof(FanOutFanInExample))] public static

    async Task<string[]> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var tasks = new List<Task<string>>(); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionA), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionB), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionC), null)); var results = await Task.WhenAll(tasks); return results; }
  12. @MarcDuiker 57 public static class FanOutFanInExample { [FunctionName(nameof(FanOutFanInExample))] public static

    async Task<string[]> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var tasks = new List<Task<string>>(); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionA), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionB), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionC), null)); var results = await Task.WhenAll(tasks); return results; }
  13. @MarcDuiker 58 public static class FanOutFanInExample { [FunctionName(nameof(FanOutFanInExample))] public static

    async Task<string[]> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var tasks = new List<Task<string>>(); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionA), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionB), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionC), null)); var results = await Task.WhenAll(tasks); return results; }
  14. @MarcDuiker 59 public static class FanOutFanInExample { [FunctionName(nameof(FanOutFanInExample))] public static

    async Task<string[]> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var tasks = new List<Task<string>>(); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionA), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionB), null)); tasks.Add(context.CallActivityAsync<string>( nameof(ActivityFunctionC), null)); var results = await Task.WhenAll(tasks); return results; }
  15. @MarcDuiker 61 public static class SubOrchestratorExample { [FunctionName(nameof(SubOrchestratorExample))] public static

    async Task<string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var resultA = await context.CallSubOrchestratorAsync<string>( nameof(SubOrchestratorA), null); var resultB = await context.CallSubOrchestratorAsync<string>( nameof(SubOrchestratorB), resultA); var resultC = await context.CallSubOrchestratorAsync<string>( nameof(SubOrchestratorC), resultC); return resultC; } }
  16. @MarcDuiker 66 Domain Bounded Context Bounded Context Bounded Context Bounded

    Context https://thedomaindrivendesign.io/bounded-context/
  17. @MarcDuiker 68 “Ubiquitous language identifies the terms and concepts within

    a bounded context that are unambiguous and agreed upon by all stakeholders.” https://thedomaindrivendesign.io/what-is-strategic-design
  18. @MarcDuiker 75 “Resilience is the ability to provide and maintain

    an acceptable level of service in the face of faults and challenges to normal operation.” https://en.wikipedia.org/wiki/Resilience_(network)
  19. @MarcDuiker 81 public static class ChainingWithRetryExample { [FunctionName(nameof(ChainingWithRetryExample))] public static

    async Task<string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var resultA = await context.CallActivityWithRetryAsync<string>( nameof(ActivityFunctionA), new RetryOptions(TimeSpan.FromSeconds(5), 3) { BackoffCoefficient = 2 }, null); var resultB = await context.CallActivityAsync<string>( nameof(ActivityFunctionB), resultA); var resultC = await context.CallActivityAsync<string>( nameof(ActivityFunctionC), resultB); return resultC; } }
  20. @MarcDuiker 82 public static class ChainingWithRetryExample { [FunctionName(nameof(ChainingWithRetryExample))] public static

    async Task<string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var resultA = await context.CallActivityWithRetryAsync<string>( nameof(ActivityFunctionA), new RetryOptions(TimeSpan.FromSeconds(5), 3) { BackoffCoefficient = 2 }, null); var resultB = await context.CallActivityAsync<string>( nameof(ActivityFunctionB), resultA); var resultC = await context.CallActivityAsync<string>( nameof(ActivityFunctionC), resultB); return resultC; } }
  21. @MarcDuiker 91 App Settings: FUNCTIONS_WORKER_PROCESS_COUNT Function App resource property: functionAppScaleLimit

    https://learn.microsoft.com/en-us/azure/azure-functions/event-driven-scaling https://learn.microsoft.com/en-us/azure/azure-functions/functions-best-practices SCALE_CONTROLLER_LOGGING_ENABLED
  22. @MarcDuiker - Monitor your agility! - Ask yourself these questions

    before adding any code: - Do *I* need to write this? - Is this a good fit with the rest of the app? - What is the impact regarding resilience/scalability of the app?