Skip to content

Instantly share code, notes, and snippets.

@0xdevalias
Last active April 28, 2025 01:41
Show Gist options
  • Save 0xdevalias/674478c02c10b0b8d0bfad317d782620 to your computer and use it in GitHub Desktop.
Save 0xdevalias/674478c02c10b0b8d0bfad317d782620 to your computer and use it in GitHub Desktop.
Some notes on Azure serverless functions and related features/patterns/etc

Azure serverless functions and related features/patterns/etc

Some notes on Azure serverless functions and related features/patterns/etc

Table of Contents

Architecture Design Patterns

  • https://learn.microsoft.com/en-us/azure/architecture/patterns/
    • Cloud design patterns

    • Architects design workloads by integrating platform services, functionality, and code to meet both functional and nonfunctional requirements. To design effective workloads, you must understand these requirements and select topologies and methodologies that address the challenges of your workload's constraints. Cloud design patterns provide solutions to many common challenges.

      System design heavily relies on established design patterns. You can design infrastructure, code, and distributed systems by using a combination of these patterns. These patterns are crucial for building reliable, highly secure, cost-optimized, operationally efficient, and high-performing applications in the cloud.

      The following cloud design patterns are technology-agnostic, which makes them suitable for any distributed system. You can apply these patterns across Azure, other cloud platforms, on-premises setups, and hybrid environments.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/async-request-reply
      • Asynchronous Request-Reply pattern

      • Decouple backend processing from a frontend host, where backend processing needs to be asynchronous, but the frontend still needs a clear response.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker
      • Circuit Breaker pattern

      • The Circuit Breaker pattern helps handle faults that might take varying amounts of time to recover from when an application connects to a remote service or resource. A circuit breaker temporarily blocks access to a faulty service after it detects failures. This action prevents repeated unsuccessful attempts so that the system can recover effectively. This pattern can improve the stability and resiliency of an application.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/claim-check
      • Claim-Check pattern

      • The Claim-Check pattern allows workloads to transfer payloads without storing the payload in a messaging system. The pattern stores the payload in an external data store and uses a "claim check" to retrieve the payload. The claim check is a unique, obscure token or key. To retrieve the payload, applications need to present the claim-check token to the external data store.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/competing-consumers
      • Competing Consumers pattern

      • Enable multiple concurrent consumers to process messages received on the same messaging channel. With multiple concurrent consumers, a system can process multiple messages concurrently to optimize throughput, to improve scalability and availability, and to balance the workload.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs
      • CQRS pattern

      • Command Query Responsibility Segregation (CQRS) is a design pattern that segregates read and write operations for a data store into separate data models. This approach allows each model to be optimized independently and can improve the performance, scalability, and security of an application.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/event-sourcing
      • Event Sourcing pattern

      • Instead of storing just the current state of the data in a relational database, store the full series of actions taken on an object in an append-only store. The store acts as the system of record and can be used to materialize the domain objects. This approach can improve performance, scalability, and auditability in complex systems.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/external-configuration-store
      • External Configuration Store pattern

      • Move configuration information out of the application deployment package to a centralized location. This can provide opportunities for easier management and control of configuration data, and for sharing configuration data across applications and application instances.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/federated-identity
      • Federated Identity pattern

      • Delegate authentication to an external identity provider. This can simplify development, minimize the requirement for user administration, and improve the user experience of the application.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/health-endpoint-monitoring
      • Health Endpoint Monitoring pattern

      • To verify that applications and services are performing correctly, you can use the Health Endpoint Monitoring pattern. This pattern specifies the use of functional checks in an application. External tools can access these checks at regular intervals through exposed endpoints.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/messaging-bridge
      • Messaging Bridge pattern

      • This article describes the Messaging Bridge pattern, which is a technique that you can use to integrate disparate systems that are built on top of different messaging infrastructures.

      • In this scenario, each system connects to one messaging infrastructure. To integrate across different messaging infrastructures, introduce a bridge component that connects to two or more messaging infrastructures at the same time. The bridge pulls messages from one and pushes them to the other without changing the payload.

        The systems being integrated don't need to recognize the others or the bridge. The sender system is configured to send specific messages to a designated queue on its native messaging infrastructure. The bridge picks up those messages and forwards them to another queue in a different messaging infrastructure where the receiver system picks them up.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/pipes-and-filters
      • Pipes and Filters pattern

      • Decompose a task that performs complex processing into a series of separate elements that can be reused. Doing so can improve performance, scalability, and reusability of initial steps by allowing task elements that perform the processing to be deployed and scaled independently. Pipes and Filters pattern supports a high level of modularity.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/priority-queue
      • Priority Queue pattern

      • The priority queue pattern enables a workload to process high-priority tasks more quickly than lower-priority tasks. This pattern uses messages sent to one or more queues and is useful in applications that offer different service level guarantees to individual clients.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/publisher-subscriber
      • Publisher-Subscriber pattern

      • Enable an application to announce events to multiple interested consumers asynchronously, without coupling the senders to the receivers.

        Also called: Pub/sub messaging

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/queue-based-load-leveling
      • Queue-Based Load Leveling pattern

      • Use a queue that acts as a buffer between a task and a service it invokes in order to smooth intermittent heavy loads that can cause the service to fail or the task to time out. This can help to minimize the impact of peaks in demand on availability and responsiveness for both the task and the service.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/rate-limiting-pattern
      • Rate Limiting pattern

      • Many services use a throttling pattern to control the resources they consume, imposing limits on the rate at which other applications or services can access them. You can use a rate limiting pattern to help you avoid or minimize throttling errors related to these throttling limits and to help you more accurately predict throughput.

        A rate limiting pattern is appropriate in many scenarios, but it is particularly helpful for large-scale repetitive automated tasks such as batch processing.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/retry
      • Retry pattern

      • Enable an application to handle transient failures when it tries to connect to a service or network resource, by transparently retrying a failed operation. This can improve the stability of the application.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/saga
      • Saga distributed transactions pattern

      • The Saga design pattern helps maintain data consistency in distributed systems by coordinating transactions across multiple services. A saga is a sequence of local transactions where each service performs its operation and initiates the next step through events or messages. If a step in the sequence fails, the saga performs compensating transactions to undo the completed steps. This approach helps maintain data consistency.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/scheduler-agent-supervisor
      • Scheduler Agent Supervisor pattern

      • Coordinate a set of distributed actions as a single operation. If any of the actions fail, try to handle the failures transparently, or else undo the work that was performed, so the entire operation succeeds or fails as a whole. This can add resiliency to a distributed system, by enabling it to recover and retry actions that fail due to transient exceptions, long-lasting faults, and process failures.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/sequential-convoy
      • Sequential Convoy pattern

      • Process a set of related messages in a defined order, without blocking processing of other groups of messages.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/sharding
      • Sharding pattern

      • Divide a data store into a set of horizontal partitions or shards. This can improve scalability when storing and accessing large volumes of data.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/sidecar
      • Sidecar pattern

      • Deploy components of an application into a separate process or container to provide isolation and encapsulation. This pattern can also enable applications to be composed of heterogeneous components and technologies.

        This pattern is named Sidecar because it resembles a sidecar attached to a motorcycle. In the pattern, the sidecar is attached to a parent application and provides supporting features for the application. The sidecar also shares the same lifecycle as the parent application, being created and retired alongside the parent. The sidecar pattern is sometimes referred to as the sidekick pattern and is a decomposition pattern.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/strangler-fig
      • Strangler Fig pattern

      • This pattern incrementally migrates a legacy system by gradually replacing specific pieces of functionality with new applications and services. As you replace features from the legacy system, the new system eventually comprises all of the old system's features. This approach suppresses the old system so that you can decommission it.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/throttling
      • Throttling pattern

      • Control the consumption of resources used by an instance of an application, an individual tenant, or an entire service. This can allow the system to continue to function and meet service level agreements, even when an increase in demand places an extreme load on resources.

    • https://learn.microsoft.com/en-us/azure/architecture/patterns/valet-key
      • Valet Key pattern

      • Use a token that provides clients with restricted direct access to a specific resource, in order to offload data transfer from the application. This is particularly useful in applications that use cloud-hosted storage systems or queues, and can minimize cost and maximize scalability and performance.

Durable Functions

RE: Securing Functions

RE: Global Rate Limiting for Parallel File Processing in Azure Functions

Related docs/etc:

  • https://learn.microsoft.com/en-us/azure/azure-functions/durable/
    • Azure Durable Functions documentation Durable Functions is an extension of Azure Functions that lets you write stateful functions in a serverless compute environment.

  • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview
    • What are Durable Functions?

    • Durable Functions is a feature of Azure Functions that lets you write stateful functions in a serverless compute environment. The extension lets you define stateful workflows by writing orchestrator functions and stateful entities by writing entity functions using the Azure Functions programming model. Behind the scenes, the extension manages state, checkpoints, and restarts for you, allowing you to focus on your business logic.

    • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview#monitoring
      • Pattern #4: Monitor

      • The monitor pattern refers to a flexible, recurring process in a workflow. An example is polling until specific conditions are met. You can use a regular timer trigger to address a basic scenario, such as a periodic cleanup job, but its interval is static and managing instance lifetimes becomes complex. You can use Durable Functions to create flexible recurrence intervals, manage task lifetimes, and create multiple monitor processes from a single orchestration.

      • The monitors can end execution when a condition is met, or another function can use the durable orchestration client to terminate the monitors. You can change a monitor's wait interval based on a specific condition (for example, exponential backoff.)

        • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-bindings#orchestration-client
          • Orchestration client The orchestration client binding enables you to write functions that interact with orchestrator functions. These functions are often referred to as client functions. For example, you can act on orchestration instances in the following ways:

            • Start them
            • Query their status.
            • Terminate them.
            • Send events to them while they're running.
            • Purge instance history.

            You can bind to the orchestration client by using the DurableClientAttribute attribute

    • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview#human
      • Pattern #5: Human interaction

      • Many automated processes involve some kind of human interaction. Involving humans in an automated process is tricky because people aren't as highly available and as responsive as cloud services. An automated process might allow for this interaction by using timeouts and compensation logic.

        An approval process is an example of a business process that involves human interaction. Approval from a manager might be required for an expense report that exceeds a certain dollar amount. If the manager doesn't approve the expense report within 72 hours (might be the manager went on vacation), an escalation process kicks in to get the approval from someone else (perhaps the manager's manager).

      • You can implement the pattern in this example by using an orchestrator function. The orchestrator uses a durable timer to request approval. The orchestrator escalates if timeout occurs. The orchestrator waits for an external event, such as a notification that's generated by a human interaction.

      • Note: There is no charge for time spent waiting for external events when running in the Consumption plan.

    • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview#aggregator
      • Pattern #6: Aggregator (stateful entities) The sixth pattern is about aggregating event data over a period of time into a single, addressable entity. In this pattern, the data being aggregated might come from multiple sources, might be delivered in batches, or might be scattered over long-periods of time. The aggregator might need to take action on event data as it arrives, and external clients might need to query the aggregated data.

      • You can use Durable entities to easily implement this pattern as a single function.

        • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-entities
          • Entity functions Entity functions define operations for reading and updating small pieces of state, known as durable entities. Like orchestrator functions, entity functions are functions with a special trigger type, the entity trigger. Unlike orchestrator functions, entity functions manage the state of an entity explicitly, rather than implicitly representing state via control flow. Entities provide a means for scaling out applications by distributing the work across many entities, each with a modestly sized state.

      • Clients can enqueue operations for (also known as "signaling") an entity function using the entity client binding.

    • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview#the-technology
      • The technology Behind the scenes, the Durable Functions extension is built on top of the Durable Task Framework, an open-source library on GitHub that's used to build workflows in code. Like Azure Functions is the serverless evolution of Azure WebJobs, Durable Functions is the serverless evolution of the Durable Task Framework. Microsoft and other organizations use the Durable Task Framework extensively to automate mission-critical processes. It's a natural fit for the serverless Azure Functions environment.

      • https://github.com/Azure/durabletask
        • Durable Task Framework The Durable Task Framework (DTFx) is a library that allows users to write long running persistent workflows (referred to as orchestrations) in C# using simple async/await coding constructs. It is used heavily within various teams at Microsoft to reliably orchestrate long running provisioning, monitoring, and management operations. The orchestrations scale out linearly by simply adding more worker machines. This framework is also used to power the serverless Durable Functions extension of Azure Functions.

    • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview#code-constraints
      • Code constraints In order to provide reliable and long-running execution guarantees, orchestrator functions have a set of coding rules that must be followed. For more information, see the Orchestrator function code constraints article.

        • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-code-constraints
          • Orchestrator function code constraints

          • Orchestrator functions use event sourcing to ensure reliable execution and to maintain local variable state. The replay behavior of orchestrator code creates constraints on the type of code that you can write in an orchestrator function. For example, orchestrator functions must be deterministic: an orchestrator function will be replayed multiple times, and it must produce the same result each time.

          • Orchestrator functions can call any API in their target languages. However, it's important that orchestrator functions call only deterministic APIs. A deterministic API is an API that always returns the same value given the same input, no matter when or how often it's called.

          • These restrictions apply only to orchestrator functions. Other function types don't have such restrictions.

          • An orchestrator function must not use any bindings, including even the orchestration client and entity client bindings. Always use input and output bindings from within a client or activity function. This is important because orchestrator functions may be replayed multiple times, causing nondeterministic and duplicate I/O with external systems.

          • Use activity functions to make outbound network calls. If you need to make an HTTP call from your orchestrator function, you also can use the durable HTTP APIs.

          • Blocking APIs like "sleep" can cause performance and scale problems for orchestrator functions and should be avoided. In the Azure Functions Consumption plan, they can even result in unnecessary execution time charges. Use alternatives to blocking APIs when they're available. For example, use Durable timers to create delays that are safe for replay and don't count towards the execution time of an orchestrator function.

          • Orchestrator code must never start any async operation except those defined by the orchestration trigger's context object. For example, never use Task.Run, Task.Delay, and HttpClient.SendAsync in .NET or setTimeout and setInterval in JavaScript. An orchestrator function should only schedule async work using Durable SDK APIs, like scheduling activity functions. Any other type of async invocations should be done inside activity functions.

          • Always declare JavaScript orchestrator functions as synchronous generator functions. You must not declare JavaScript orchestrator functions as async because the Node.js runtime doesn't guarantee that asynchronous functions are deterministic.

          • You must not declare Python orchestrator functions as coroutines. In other words, never declare Python orchestrator functions with the async keyword because coroutine semantics do not align with the Durable Functions replay model. You must always declare Python orchestrator functions as generators, meaning that you should expect the context API to use yield instead of await.

          • A durable orchestration might run continuously for days, months, years, or even eternally. Any code updates made to Durable Functions apps that affect unfinished orchestrations might break the orchestrations' replay behavior. That's why it's important to plan carefully when making updates to code.

          • https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-code-constraints?#durable-tasks
            • Durable tasks

            • Note: This section describes internal implementation details of the Durable Task Framework. You can use durable functions without knowing this information. It is intended only to help you understand the replay behavior.

            • Tasks that can safely wait in orchestrator functions are occasionally referred to as durable tasks. The Durable Task Framework creates and manages these tasks. Examples are the tasks returned by CallActivityAsync, WaitForExternalEvent, and CreateTimer in .NET orchestrator functions.

  • https://learn.microsoft.com/en-us/azure/architecture/patterns/rate-limiting-pattern
  • https://learn.microsoft.com/en-us/azure/architecture/patterns/throttling
    • Throttling pattern

    • As above; I skimmed through this, and while it talks about the right sort of things at a high level, it doesn't necessarily go into a great lot of useful detail
    • Queue-based Load Leveling pattern. Queue-based load leveling is a commonly used mechanism for implementing throttling. A queue can act as a buffer that helps to even out the rate at which requests sent by an application are delivered to a service.

  • https://medium.com/microsoftazure/azure-functions-limiting-throughput-and-scalability-of-a-serverless-app-5b1c381491e3
    • Azure functions. Limiting throughput and scalability of a serverless app

    • TL;DR. You will get info on how to limit incoming incoming HTTP traffic to Serverless API and messages stream from Azure IoT Hub. And how to enforce restriction to Azure Functions scale-out and why singleton attribute might be needed.

    • Skimmed through this, while some of the ideas are sort of ok, most of them I didn't really like the sound of. Probably not a good solution, but kept here as reference in case.
  • https://learn.microsoft.com/en-us/azure/architecture/patterns/retry
    • Retry pattern Enable an application to handle transient failures when it tries to connect to a service or network resource, by transparently retrying a failed operation. This can improve the stability of the application.

    • Retry after delay. If the fault is caused by one of the more commonplace connectivity or busy failures, the network or service might need a short period while the connectivity issues are corrected or the backlog of work is cleared. The application should wait for a suitable time before retrying the request.

    • If the request still fails, the application can wait and make another attempt. If necessary, this process can be repeated with increasing delays between retry attempts, until some maximum number of requests have been attempted. The delay can be increased incrementally or exponentially, depending on the type of failure and the probability that it'll be corrected during this time.

    • If a request still fails after a significant number of retries, it's better for the application to prevent further requests going to the same resource and simply report a failure immediately. When the period expires, the application can tentatively allow one or more requests through to see whether they're successful. For more details of this strategy, see the Circuit Breaker pattern.

      • https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker
        • Circuit Breaker pattern Handle faults that might take a variable amount of time to recover from, when connecting to a remote service or resource. This can improve the stability and resiliency of an application.

        • A circuit breaker acts as a proxy for operations that might fail. The proxy should monitor the number of recent failures that have occurred, and use this information to decide whether to allow the operation to proceed, or simply return an exception immediately.

        • The proxy can be implemented as a state machine with the following states that mimic the functionality of an electrical circuit breaker:

          Closed: The request from the application is routed to the operation. The proxy maintains a count of the number of recent failures, and if the call to the operation is unsuccessful the proxy increments this count. If the number of recent failures exceeds a specified threshold within a given time period, the proxy is placed into the Open state. At this point the proxy starts a timeout timer, and when this timer expires the proxy is placed into the Half-Open state.

          The purpose of the timeout timer is to give the system time to fix the problem that caused the failure before allowing the application to try to perform the operation again.

          Open: The request from the application fails immediately and an exception is returned to the application.

          Half-Open: A limited number of requests from the application are allowed to pass through and invoke the operation. If these requests are successful, it's assumed that the fault that was previously causing the failure has been fixed and the circuit breaker switches to the Closed state (the failure counter is reset). If any request fails, the circuit breaker assumes that the fault is still present so it reverts to the Open state and restarts the timeout timer to give the system a further period of time to recover from the failure.

  • https://learn.microsoft.com/en-us/azure/architecture/patterns/competing-consumers
    • Competing Consumers pattern Enable multiple concurrent consumers to process messages received on the same messaging channel. With multiple concurrent consumers, a system can process multiple messages concurrently to optimize throughput, to improve scalability and availability, and to balance the workload.

  • https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-error-pages
    • Azure Functions error handling and retries

    • ⚠️ TODO: go through these docs + add relevant snippets here; particularly with regards to how azure functions + queues handle error states, retries, retry delays, etc

Some other notes:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment