HTTP-Triggered Workflow Design

Design an HTTP-triggered workflow in Azure. Learn the core concept, step-by-step implementation, hands-on exercise, and troubleshooting—then move to the next lesson.

Focus: design an http-triggered workflow

Sponsored

Imagine you've just deployed a small API endpoint in Azure, and the next natural step is to kick off a series of background tasks every time that endpoint gets called—send a confirmation email, update a database, call another service. You could write all that logic directly inside your function, but that's a maintenance nightmare. You'd be mixing concerns, duplicating code, and making it nearly impossible to trace what happens after the request arrives. The pain is real: without a deliberate design, your HTTP-triggered workflow becomes a tangled mess of callbacks, retries, and polling loops that break in production. This lesson gives you a clean, battle-tested approach to design an HTTP-triggered workflow in Azure—so you can turn a simple web request into a reliable, observable pipeline.

The Problem This Lesson Solves

Most developers start by bolting workflow logic onto their HTTP endpoint. The function receives a request, does some work, maybe fires a message to a queue, and hopes everything lines up. But real-world workflows are rarely that simple:

  • Long-running tasks—like video encoding or report generation—can exceed HTTP timeout limits (typically 230 seconds for Azure Functions, 60 seconds for some services).
  • Partial failures—the request succeeds, but a downstream step fails, leaving your system in an inconsistent state.
  • Tight coupling—the HTTP trigger knows too much about the implementation details of every step, making the system brittle and hard to test.

Pro tip: The core problem isn't how to trigger a workflow—it's how to decouple the trigger from the work so that each step can scale, retry, and fail independently.

This lesson solves that by teaching you a design pattern: use an HTTP trigger to receive a request, validate it, and immediately hand off the real work to a background process (like a queue, durable function, or Logic App). That way, your endpoint stays fast, your workflow becomes observable, and your system stays resilient.

Core Concept / Mental Model

Think of an HTTP-triggered workflow like a restaurant order.

  • The HTTP trigger is the waiter who takes your order at the table. They don't cook the food—they just record what you asked for and pass it to the kitchen.
  • The workflow orchestrator is the kitchen manager. They decide which dishes to prepare, in what order, and what to do if an ingredient is missing.
  • The worker steps are the individual cooks—each handles one task (chop vegetables, grill steak, plate the dish). They don't need to talk to the waiter directly; they just receive instructions from the manager.

In Azure, the waiter is your HTTP-triggered function (or Logic App HTTP endpoint). The kitchen manager might be an Azure Durable Functions orchestrator, a Logic App, or an Azure Storage Queue feeding into a worker function. The cooks are separate functions or services that each perform a single, focused action.

Key definitions: - HTTP trigger: A function endpoint that responds to an HTTP request (GET, POST, etc.) and returns a response to the caller. - Orchestrator: A component that coordinates the sequence of steps, manages state, and handles retries/side effects. - Activity: A single unit of work (e.g., call an API, write to a database) that the orchestrator invokes.

This mental model separates receiving the request from processing it. That separation is what makes your workflow designable, testable, and scalable.

How It Works Step by Step

Here's how to design an HTTP-triggered workflow in Azure, step by step. We'll use Azure Functions with Durable Functions as the reference implementation, but the principles apply to Logic Apps and other tools.

Step 1: Decide on the trigger pattern

Your HTTP trigger should do the absolute minimum:

  1. Validate the request—check authentication, required fields, and payload format.
  2. Start the orchestration—call the orchestrator function (or post a message to a queue).
  3. Return a fast response—either a simple "Accepted" (202) or the orchestration status URL.

Step 2: Choose your orchestration mechanism

You have three common options:

  • Durable Functions: Best for complex, stateful workflows with multiple steps, conditional branching, and human interaction.
  • Azure Logic Apps: Great for low-code workflows that integrate with many SaaS services.
  • Storage Queue + Worker: Simple, cost-effective for fire-and-forget tasks with limited state needs.

Step 3: Define your workflow steps

List every action that must happen after the HTTP request arrives. For example, for an order processing workflow:

  1. Validate order data
  2. Charge payment
  3. Update inventory
  4. Send confirmation email

Each step should be an idempotent, stateless function (or API call). If possible, make each step retryable without side effects.

Step 4: Implement the HTTP trigger and orchestrator

In your function app, you'll have:

  • An HTTP-triggered function that starts the orchestration.
  • An orchestrator function that defines the sequence of activities.
  • Activity functions for each step.

The orchestrator uses a generator-based pattern (in C#) or async/await (in Python) to yield control, allowing Azure to checkpoint state and resume on failure.

Hands-On Walkthrough

Let's build a simple HTTP-triggered workflow using Azure Functions and Durable Functions in Python. We'll create a function app with an HTTP trigger that starts a durable orchestration, and an orchestrator that calls two activity functions: one to format a message, and one to log it.

Prerequisites

Create a new Functions project

func init HttpWorkflowDemo --worker-runtime python --model v2
cd HttpWorkflowDemo

Add Durable Functions extension

func extensions install -p Microsoft.Azure.WebJobs.Extensions.DurableTask -v 2.13.5

Write the HTTP trigger function

Create a file http_start/__init__.py:

import azure.functions as func
import azure.durable_functions as df

async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
    # Validate request
    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
            name = req_body.get('name')
        except ValueError:
            pass
    if not name:
        return func.HttpResponse("Please pass a name in the query string or in the request body", status_code=400)

    # Start orchestration
    instance_id = await df.start_new(starter, None, name)

    # Return status URL
    return func.HttpResponse(f"Started orchestration. Check status at: /api/orchestrators/{instance_id}", status_code=202)

Write the orchestrator function

Create orchestrator/__init__.py:

import azure.durable_functions as df


def orchestrator_function(context: df.DurableOrchestrationContext):
    name = context.get_input()

    # Step 1: Format message
    formatted = yield context.call_activity('format_message', name)

    # Step 2: Log message (simulate processing)
    result = yield context.call_activity('process_message', formatted)

    return result

main = df.Orchestrator.create(orchestrator_function)

Write activity functions

Create format_message/__init__.py:

import azure.functions as func
import azure.durable_functions as df

def main(name: str) -> str:
    return f"Hello, {name}!"

Create process_message/__init__.py:

import azure.functions as func
import azure.durable_functions as df

def main(message: str) -> str:
    # Simulate some work
    import time
    time.sleep(2)
    return f"Processed: {message}"

Run locally and test

func start

Then, in another terminal:

curl -X POST "http://localhost:7071/api/orchestrators/HttpStart" -d '{"name": "Azure"}' -H "Content-Type: application/json"

Expected output:

{
  "id": "abc123",
  "statusQueryGetUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/abc123?taskHub=TestHubName&connection=Storage&code=...",
  "sendEventPostUri": "...",
  "terminatePostUri": "..."
}

You can poll the statusQueryGetUri to see the workflow progress. After a few seconds it should report status: "Completed" with the final output.

Compare Options / When to Choose What

The table below compares the main orchestration mechanisms for HTTP-triggered workflows.

Approach Strengths Weaknesses Best For
Durable Functions Stateful, checkpoints, retries, human interaction, fan-out/fan-in More complex, requires code Complex, multi-step workflows with strict consistency
Azure Logic Apps Low-code, many connectors, visual designer Limited control flow, can be costly at scale Integration-heavy workflows with SaaS apps
Queue + Worker Simple, cheap, decoupled No built-in state, manual recovery Fire-and-forget tasks, simple pipelines
HTTP + WebJobs Minimal dependencies Not serverless, lack of orchestration Legacy apps with simple background processing

Rule of thumb: If your workflow has more than two steps or needs conditional logic, go with Durable Functions. If it's a simple async task (like sending an email after a signup), a queue is enough.

Variations

  • Use Durable Functions with a synchronous HTTP pattern—return the final result of the workflow in the HTTP response via the AsyncHttpTrigger pattern. Great for short-lived workflows where the client wants the final answer.
  • Use Azure Logic Apps with a webhook trigger—this allows two-way communication with external services that need callbacks.
  • Combine Azure Functions with Azure Service Bus—instead of a simple queue, use a topic to publish events and have multiple subscribers react independently.

Troubleshooting & Edge Cases

Even a well-designed workflow can hit issues. Here are the most common ones and how to fix them.

1. "Function timeout" or HTTP 500 after ~230 seconds

If your HTTP trigger does long-running work instead of handing off to the orchestrator, it will time out. Solution: Always start the orchestrator and return immediately (202). If you need the final result synchronously, use the AsyncHttpTrigger pattern (see Variations).

2. Orchestrator replays cause side effects

Durable Functions replay the orchestrator code multiple times for checkpointing. If you call a non-deterministic API inside the orchestrator (e.g., DateTime.Now or Random), you'll get inconsistent results. Solution: Only call activity functions or deterministic APIs inside the orchestrator.

3. Activity function fails, but the workflow doesn't retry

By default, activities retry when an exception is thrown, but only if you configure retry policies. If your activity fails silently (e.g., catches and suppresses errors), the workflow may continue incorrectly. Solution: Let exceptions propagate, and use RetryOptions (e.g., maxRetryInterval, maxNumberOfAttempts) in your orchestration context.

4. Payload too large for queue/orchestration input

The orchestration input is stored in Azure Storage and has size limits. Passing a 100 MB request body directly will fail. Solution: Store large payloads in Blob Storage and pass only the blob URL to the orchestrator.

5. Authentication and authorization

Don't rely on the HTTP trigger's default function key for security. For production, use Azure AD with Managed Identity and authorize at the API Management layer or with Microsoft Entra.

What You Learned & What's Next

You've now got a solid foundation to design an HTTP-triggered workflow in Azure. Let's recap the key concepts you've mastered:

  • Separate the trigger from the work: The HTTP trigger only validates and starts the workflow; the orchestrator manages the steps.
  • Use Durable Functions (or Logic Apps/Queues) to manage state and retries: This gives you reliability at scale.
  • Implement best practices like idempotent activities and proper retries to make your workflow production-ready.

You also completed a hands-on exercise that built a working HTTP-triggered durable function, then compared it to alternative approaches.

Now you're ready for the next lesson in the Azure Tutorial track: typically, that involves connecting your HTTP-triggered workflow to Azure Blob Storage or Service Bus to exchange data with other components. You'll build on the decoupling pattern you just learned—so keep that mental model of waiter, manager, and cooks in mind!

Final pro tip: Always design your workflow with observability in mind. Use Application Insights to track each step's execution time, failures, and custom events. When something breaks in production, you'll be glad you did.

Now go ahead and try the practice below to cement your skills.

Practice Recap

Modify the workflow you built to include a new activity that calls an external API (e.g., a mock endpoint that returns a success flag). Use the call_activity function inside the orchestrator and add a RetryOptions to handle a 429 response. Test it locally and observe how the retry policy behaves by temporarily making the external API fail. This will solidify your understanding of retries and failure handling in orchestrated workflows.

Practice recap

Modify the workflow you built to include a new activity that calls an external API (e.g., a mock endpoint that returns a success flag). Use the call_activity function inside the orchestrator and add a RetryOptions to handle a 429 response. Test it locally and observe how the retry policy behaves by temporarily making the external API fail. This will solidify your understanding of retries and failure handling in orchestrated workflows.

Common mistakes

  • Doing heavy work directly inside the HTTP trigger function, causing timeouts and blocking the response.
  • Calling non-deterministic functions (like DateTime.Now) inside the orchestrator, leading to inconsistent state on replays.
  • Swallowing exceptions in activity functions, preventing retries and leaving the workflow in an unknown state.
  • Passing large payloads directly to the orchestrator, exceeding Azure Storage limits.

Variations

  1. Synchronous HTTP pattern with AsyncHttpTrigger to return the final workflow result in the HTTP response.
  2. Using Azure Logic Apps with a webhook trigger for two-way callbacks.
  3. Combining Azure Functions with Azure Service Bus topics for event-driven fan-out.

Real-world use cases

  • Order processing workflow that validates payment, updates inventory, and sends confirmation emails asynchronously after an HTTP POST order.
  • Video processing pipeline where an HTTP upload triggers encoding, thumbnail generation, and notification steps in a durable function.
  • Report generation service where an HTTP request kicks off a multi-step workflow that queries databases, compiles a PDF, and stores it in Blob Storage.

Key takeaways

  • Keep your HTTP trigger thin: validate, start the orchestration, and respond quickly.
  • Use Durable Functions for complex, stateful workflows with retries and checkpoints.
  • Separate concerns by making each workflow step an idempotent activity function.
  • Choose the orchestration tool based on complexity, integrations, and cost—Durable Functions, Logic Apps, or Queue + Worker.
  • Handle edge cases like timeouts, non-deterministic code, and large payloads proactively.
  • Design for observability from day one with Application Insights.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.