Graph-Driven Automation with Azure Functions

What you will build

A serverless automation that reacts to Microsoft Graph data changes, processes them, persists workflow state, and produces downstream artifacts. This is a general-purpose pattern for any scenario where Graph is the data source and short-lived compute is the right execution model.

Scenario

You have data in Microsoft Graph that changes over time: group memberships shift, application assignments update, user lifecycle events occur. You need code that periodically checks for changes, processes them, tracks what has been handled, and writes results somewhere a downstream system or operator can pick them up.

Examples:

  • Sync group membership changes to an external system’s access list
  • React to new application assignments by provisioning resources
  • Export user lifecycle data for compliance reporting

Why Azure Functions fits

The work is event-driven and short-lived. Each execution follows the same shape:

  • A timer fires or an HTTP request arrives
  • The function calls Graph to read current state
  • It compares against stored checkpoints
  • It processes the delta
  • It writes state and artifacts
  • It finishes

That shape matches Azure Functions better than a permanently running service. You get managed triggers, automatic scaling on demand, and no idle cost between runs.

Architecture

sequenceDiagram
    autonumber
    participant Trigger as Timer or HTTP Trigger
    participant Func as Azure Functions
    participant Graph as Microsoft Graph
    participant Cosmos as Cosmos DB
    participant Blob as Azure Storage
    participant Target as Downstream System

    Trigger->>Func: Invoke function
    Func->>Cosmos: Read last checkpoint
    Cosmos-->>Func: Checkpoint state
    Func->>Graph: Query changes since checkpoint
    Graph-->>Func: Changed data
    Func->>Func: Process and validate changes
    Func->>Cosmos: Upsert workflow state + new checkpoint
    Func->>Blob: Write export artifact (CSV, JSON, manifest)
    Func->>Target: Notify or submit artifact reference
    Func-->>Trigger: Return status

Each service has a clear role:

  • Microsoft Graph is the data source. It tells you what changed but does not own the workflow around those changes.
  • Azure Functions runs the glue logic, scoped to a bounded unit of work.
  • Cosmos DB stores durable state: checkpoints, retry counts, correlation IDs, processing progress.
  • Azure Storage stores file-shaped outputs: CSVs, JSON exports, manifests, raw snapshots.

Cosmos DB vs Azure Storage

Keep the storage boundary explicit. These are different tools for different access patterns:

Use Cosmos DB forUse Azure Storage for
Workflow checkpointsExported reports and manifests
Retry counts and failure metadataRaw API response snapshots
Correlation IDs across runsLarge payloads handed to other systems
Processing status per entityFiles downloaded by operators or tools

The split matters because Cosmos DB is optimized for frequent reads and updates on structured documents (and priced on request units), while Azure Storage is optimized for large, infrequently-accessed blobs (and priced on capacity). Mixing them up costs more and queries worse.

See State and Artifacts for a deeper treatment of this boundary.

Key implementation details

Checkpointing. Store the last-processed timestamp or delta token in Cosmos DB. On each invocation, read the checkpoint first, query Graph for changes since that point, then update the checkpoint only after successful processing. This makes the function resumable after failures.

Idempotency. If the function fails after processing some items but before updating the checkpoint, it will re-process those items on the next run. Design your downstream writes to be idempotent so duplicates are harmless.

Bounded execution. Azure Functions has a maximum execution duration (5 minutes on Consumption, 10 on Premium by default). If you have more work than fits in one execution, process a batch, update the checkpoint, and let the next trigger pick up the rest.

When not to use this pattern

This pattern is wrong when:

  • The work is long-running or stateful across steps. If you need durable orchestration with human approval gates or multi-hour waits, consider Durable Functions or a Service Bus worker pattern instead.
  • The workload is continuously busy. If the function would fire every few seconds with substantial work each time, a dedicated worker process is cheaper and simpler than constant cold starts.
  • You need machine-level control. If the target system requires OS-level software, private network access, or host-bound connectors, see Hybrid Worker on VM.
  • The data is a high-volume event stream. If you are processing thousands of events per second, Event Hubs with Data Explorer is a better fit than polling Graph.
  • The downstream step needs reliable delivery. If the output is a work item that must be retried and dead-lettered on failure, route it through Service Bus rather than calling the target directly from the function.