All case studies

When Point-to-Point Integrations Stop Scaling

Moving from direct connections between Microsoft 365 and line-of-business systems to an event-driven layer on Azure

Cloud & PlatformResearch-Based24 min readPublished 20 Aug 2026Updated 21 Aug 2026

Research-Based. Built from public documentation and research rather than delivered client work.

Executive Summary

Integration debt is quieter than most technical debt. Nothing looks broken. Each connection was reasonable when it was built, and the estate degrades one sensible decision at a time.

The symptoms arrive together, usually about two years in: a flow fails overnight and nobody notices until a customer calls; a retry writes the same record twice; a batch job trips Microsoft Graph throttling and takes an unrelated integration down with it. These read as separate incidents. They are one architectural problem.

This study looks at replacing a mesh of direct connections with an event-driven layer — Service Bus for asynchronous messaging, Event Grid for notification, API Management as the front door — and is specific about what that buys, what it costs, and which integrations should be left exactly as they are.

Disclosure — research-based. The architecture and failure modes here are drawn from public Azure and Microsoft Graph documentation and from patterns that recur across this kind of estate. It is not an account of a delivered system. Figures in Business Impact are labelled Estimated, Projected or Illustrative.

01

Context

An estate reaches this point by doing the reasonable thing repeatedly. A team needs SharePoint document metadata in a line-of-business system, so they write a connection. Another team needs HR data flowing into a Power App, so they write another. Neither knows about the other, and neither should have to.

What the estate looks like

Twenty to thirty integrations, built over several years by different teams in different tools — some cloud flows, some Logic Apps, some Azure Functions, a couple of scheduled scripts running somewhere nobody has looked at recently. Each one is a direct link between two systems.

Why this is not laziness

A direct connection is the correct architecture for the first handful. Introducing messaging infrastructure to solve two integrations would be over-engineering and would rightly get pushed back on. The problem is that nobody notices the crossover point, because it does not announce itself.

The shape of the crossover

Connections grow roughly with the square of the systems involved. Six systems that all need to talk is not six integrations, it is closer to thirty. Somewhere in the teens, the cost of adding one more stops being linear, and the cost of a single system changing its API becomes an estate-wide event.

02

Problem Statement

Integrations fail silently, retry unsafely, and compete with each other for the same API quota. None of this is visible until something downstream is wrong.

The three failure modes that dominate

  • Silent failure. A run fails at 02:00. The tool records it, nobody watches the tool, and the first signal is a business user noticing missing data days later.
  • Unsafe retry. An integration times out after the downstream write has committed. The retry writes again. Now there are two records, and reconciling them is manual because nothing correlates the two attempts.
  • Shared-quota contention. Microsoft Graph throttles per tenant and per application. A batch job written without regard for other consumers exhausts the budget, and an unrelated integration starts failing. The team that gets paged did not cause the problem and cannot see the cause.

Underneath those

  • No correlation identifier spans a business transaction, so tracing a record's journey means opening several tools and matching timestamps.
  • Every integration re-implements retry and backoff, each slightly differently, and most of them incorrectly.
  • Contracts are implicit. A field rename in one system breaks consumers nobody knew existed.
  • Ownership is unclear for anything more than a year old.

What it costs

The visible cost is incident time. The larger one is that integration becomes something the organisation avoids — projects design around the estate rather than through it, which is how you end up with the twenty-first direct connection.

03

Objectives

Concrete enough to argue about later.

  • A failure is detected by monitoring rather than by a business user
  • A retry cannot create a duplicate — idempotency is a property of the design, not a convention
  • Graph consumption is visible per consumer, so contention can be attributed and managed
  • One correlation identifier follows a business transaction across every hop
  • Adding a consumer to an existing event does not require changing the producer
  • Contract changes are versioned and communicated rather than discovered by breakage
  • Every integration has a named owner and a documented failure runbook
04

Current State

The useful assessment here is not a count of integrations but a classification of them, because the answer differs by class.

ClassTypical implementationDominant failureWorth migrating?
User-triggered, synchronousCloud flow behind a buttonTimeout under loadUsually not — latency matters more than resilience
Scheduled bulk syncLogic App or script on a timerSilent failure, throttlingYes — biggest source of incidents
Reactive to a changePolling on a scheduleLatency, wasted quotaYes — the clearest fit for events
Point lookupDirect API call at read timeDownstream availabilityNo — an event layer adds nothing
File dropWatched folder plus a scriptPartial file reads, no retryCase by case

The measurement worth taking first

Before designing anything, get the actual failure rate per integration and the Graph consumption per application. Both are available and both are usually surprising — teams consistently guess wrong about which integration is the expensive one. That data changes the migration order, and it is cheap to collect.

05

AI Opportunity

Unusually for this kind of study, there is a clean and well-bounded AI use case here — and it sits in operations, not in the integration path itself.

Integration telemetry is high-volume, repetitive and full of patterns humans are bad at spotting: a failure rate creeping from 0.2% to 0.9% over three weeks is invisible on a dashboard and obvious to a model watching the series. Clustering related failures across integrations is similarly a good fit, because the correlation that matters is often between two systems nobody thought were connected.

What makes this a comfortable use case is that it is advisory and reversible. Nothing an AI system concludes here changes a message, a record or a routing decision. It raises a signal for an engineer, and if it is wrong the cost is a few minutes of investigation.

AI is appropriate

Where AI creates value

  • Anomaly detection on failure rates and latency, catching gradual degradation before it becomes an incident
  • Clustering related failures across integrations to surface a shared root cause faster than a human would correlate it
  • Predicting Graph throttling from consumption trends so a batch window can be moved before it collides
  • Drafting an incident summary from correlated telemetry for the engineer to verify and edit

What should not be automated

  • Transforming or enriching message payloads — a hallucinated field value is a data corruption that propagates silently
  • Deciding routing. Which consumer receives which event is a contract, and contracts must be deterministic
  • Automatically replaying dead-lettered messages, which is exactly where a wrong decision duplicates a financial record
  • Anything in the synchronous path, where it adds latency and a failure mode to a hop that must simply work
06

Alternatives

Three directions, plus the option of doing nothing, which is genuinely correct for part of the estate.

Option A

Consolidate tooling, keep point-to-point

Leave the topology alone. Standardise on one tool, adopt a shared retry and logging pattern, add monitoring to what exists, and assign owners.

Advantages

  • Cheapest by a wide margin
  • No new infrastructure to run
  • Fixes silent failure — the most painful symptom
  • Can be done incrementally by existing teams

Disadvantages

  • Connection count still grows quadratically
  • Producers still know their consumers
  • Shared quota contention remains
  • Does not fix duplicate writes
Cost: LowRisk: LowScalability: Poor beyond current sizeComplexity: Low

Option B

Event-driven layer with brokered messaging

Recommended

Producers publish events; consumers subscribe. Service Bus for durable asynchronous work, Event Grid for lightweight notification, API Management as the governed front door for synchronous calls.

Advantages

  • Producers stop knowing their consumers
  • Dead-lettering makes failure visible and recoverable
  • Retry and backoff handled by the broker
  • New consumers added without touching producers
  • Graph access can be funnelled and budgeted

Disadvantages

  • Real infrastructure to run and pay for
  • Eventual consistency has to be explained to the business
  • Debugging is harder — a message crossing three hops is less traceable than a single flow
  • Requires skills the team may not have
Cost: MediumRisk: MediumScalability: GoodComplexity: High

Option C

Full integration platform / iPaaS product

Buy a dedicated integration platform and migrate everything onto it, using its connectors, mapping tools and monitoring.

Advantages

  • Mature tooling out of the box
  • Vendor-supported connectors
  • Monitoring and alerting included
  • Less bespoke code to own

Disadvantages

  • Significant licensing
  • Another platform to govern and staff
  • Lock-in on mapping and orchestration logic
  • Overlaps heavily with capability already licensed in Azure and Microsoft 365
Cost: HighRisk: MediumScalability: GoodComplexity: Medium
07

Proposed Solution

An event-driven layer for the classes that benefit, and a deliberate decision to leave the rest alone.

The core idea

A producer publishes a fact — "a document was approved", "an employee record changed" — without knowing or caring who consumes it. Consumers subscribe. That single inversion removes most of the coupling, because adding a consumer stops being a change to the producer.

Choosing between the two messaging services

They are not interchangeable and picking wrongly is a common mistake:

  • Service Bus for work that must not be lost and may need ordering, sessions or transactional semantics — anything financial, anything that writes to a system of record.
  • Event Grid for lightweight, high-volume notification where the consumer will fetch detail if it cares. Reacting to a file landing in storage, for instance.

Using Service Bus for everything is expensive and slow; using Event Grid for everything loses messages you needed.

Idempotency, which is the part that actually matters

Every message carries a business idempotency key — not a message id, which changes on redelivery, but something derived from the business event. Consumers record processed keys and discard repeats. This is unglamorous and it is the single change that removes the duplicate-write class of incident entirely. It has to be designed in; it cannot be added later without touching every consumer.

Graph as a shared, budgeted resource

Graph access goes through a dedicated service that owns the app registration, applies backoff on 429 responses, and meters consumption per calling integration. Contention becomes visible and attributable instead of mysterious.

08

Solution Architecture

The components are ordinary Azure services. The design decisions worth reading are the idempotency key and the choice of broker per message class.

API Management

The front door for synchronous calls. Handles authentication, rate limiting per consumer, and contract versioning so a backend change does not immediately break callers.

Service Bus (queues and topics)

Durable asynchronous messaging for work that must not be lost. Topics allow multiple consumers per event; sessions preserve ordering where a business process requires it; dead-letter queues capture what could not be processed.

Event Grid

Lightweight notification for high-volume, low-value events where at-least-once delivery of a pointer is sufficient and the consumer fetches detail if it needs it.

Graph access service

Owns the application registration for Microsoft Graph, applies backoff on throttling responses, and meters consumption per calling integration so quota contention is attributable.

Consumer functions and Logic Apps

Subscribe to topics and perform the downstream work. Each records processed idempotency keys so redelivery is safe by construction.

Schema registry

Versioned event contracts. A breaking change is a new version published alongside the old one, not an edit in place.

Observability pipeline

Correlation identifiers, structured logs, metrics and alerting across every hop. The component that makes silent failure impossible, and the one most often deferred.

Dead-letter handling

A reviewed queue with an owner, not a folder nobody opens. Replay is a deliberate human action against a message whose idempotency key makes replay safe.

Data flow

A change occurs in a source system — a document approved in SharePoint, a record updated in a line-of-business application. The producer emits an event carrying a business idempotency key and a correlation identifier. Durable events land on a Service Bus topic; lightweight notifications go to Event Grid. Subscribers receive independently, so one slow consumer does not block another. A consumer checks the idempotency key against its processed set, discards a repeat, and otherwise performs the work — calling downstream systems through API Management or reading tenant data through the Graph access service, which applies backoff and meters usage. Failures are retried by the broker with exponential backoff and, on exhaustion, dead-lettered with the full context. The correlation identifier is carried on every hop and every log entry, so a single business transaction can be traced end to end without matching timestamps across tools.

Integrations

  • Microsoft Graph change notifications to trigger on tenant changes instead of polling for them
  • SharePoint and Microsoft 365 as event sources through Graph subscriptions
  • Power Automate retained for user-facing and low-volume flows, now consuming events rather than polling
  • Line-of-business systems fronted by API Management rather than called directly
  • Azure Monitor and Application Insights for the correlation and alerting pipeline

Security boundaries

  • Managed identities between Azure components — no connection strings or shared keys in configuration
  • API Management terminates external calls and is the only ingress to backend services
  • The Graph access service holds the application registration; individual integrations never carry tenant-wide Graph permissions
  • Per-consumer authorization on topic subscriptions, so a subscriber cannot read a topic it was not granted
  • Payloads carry identifiers rather than sensitive values wherever the consumer can fetch detail under its own authority

Human in the loop

  • Dead-letter replay is a human decision with a named owner, never automatic
  • Contract version retirement requires confirmation that no consumer is still bound to it
  • Throttling budget reallocation between integrations is an operational decision, not an automatic reassignment
09

Technology Stack

Azure-native, because the estate already runs there and adding a second platform to fix platform sprawl would be its own kind of joke.

Messaging

Azure Service BusAzure Event GridTopics and subscriptionsDead-letter queues

API

Azure API ManagementContract versioningPer-consumer rate limiting

Compute

Azure FunctionsAzure Logic AppsPower Automate

Microsoft 365

Microsoft GraphGraph change notificationsSharePointMicrosoft 365

Identity

Microsoft Entra IDManaged identitiesApplication registrations

Observability

Azure MonitorApplication InsightsCorrelation identifiersStructured logging
10

Architecture Decisions

Five decisions. The idempotency one is the one I would insist on even if everything else were descoped.

Decision 01

Require a business idempotency key on every message, designed in from the first integration

Duplicate writes caused by retry-after-partial-success were the most damaging recurring incident, and the most expensive to clean up because reconciliation is manual.

Alternatives considered

  • Rely on message id deduplication
  • Deduplicate in each consumer ad hoc
  • Business idempotency key carried on every message

Reason

A broker message id changes on redelivery across sessions, so deduplicating on it catches only the easy case. A key derived from the business event — order reference plus operation, for instance — is stable across every retry path including a full replay from dead-letter. It cannot be retrofitted cheaply, because every consumer must honour it, so it belongs in the first contract rather than the second iteration.

Benefits

  • Duplicate writes stop being possible rather than being unlikely
  • Dead-letter replay becomes safe
  • Consumers can be restarted without coordination

Trade-offs

  • Consumers must maintain a processed-key store
  • Key design requires thought per event type
  • Slightly more storage and lookup per message

Risks

  • A poorly chosen key that is not actually unique
  • Processed-key stores growing without a retention policy

Decision 02

Split messaging between Service Bus and Event Grid by delivery guarantee, not by convenience

The instinct is to standardise on one service. Both instincts — everything on Service Bus, everything on Event Grid — cause problems.

Alternatives considered

  • Service Bus for everything
  • Event Grid for everything
  • Split by delivery guarantee and payload weight

Reason

Service Bus for everything means paying for ordering and transactional semantics on high-volume notifications that do not need them. Event Grid for everything means accepting a delivery model that is wrong for financial writes. Classifying each event by whether loss is acceptable is a five-minute exercise per event and prevents both failures.

Benefits

  • Cost matches the guarantee actually required
  • Ordering available where a process needs it
  • High-volume notification stays cheap

Trade-offs

  • Two services to understand and operate
  • Developers must classify each new event
  • More documentation needed for the team

Risks

  • Misclassification putting a financial event on the wrong service
  • Classification drifting as new developers join

Decision 03

Funnel Microsoft Graph access through one service with metering

Graph throttling is applied per tenant and per application. Independent integrations were competing invisibly for the same budget, so the team paged was rarely the team responsible.

Alternatives considered

  • Each integration with its own app registration
  • Shared registration with no metering
  • One access service with backoff and per-caller metering

Reason

Separate registrations do distribute some limits but make total consumption unknowable and multiply the credentials to manage. A shared service centralises backoff — which most integrations implement incorrectly — and makes consumption attributable, which turns a mystery into a capacity conversation.

Benefits

  • Backoff implemented correctly once
  • Consumption attributable per integration
  • Fewer credentials to manage
  • Throttling becomes predictable

Trade-offs

  • A shared component in the critical path
  • Requires its own scaling and availability design
  • Teams lose direct control of their Graph calls

Risks

  • Single point of failure if not designed for availability
  • Becoming a bottleneck if scaling is an afterthought

Decision 04

Migrate by failure rate, not by ease

The natural instinct is to migrate the simplest integration first to build confidence.

Alternatives considered

  • Easiest first
  • Most business-critical first
  • Highest failure rate first

Reason

Easiest-first produces a migration with no measurable benefit, which makes the next round of funding harder to argue for. Most-critical-first concentrates risk before the team has learned the pattern. Highest-failure-rate-first delivers visible improvement early and generates the operational learning on integrations that are already unreliable — where the downside is smallest.

Benefits

  • Early visible reduction in incidents
  • Learning happens on already-unreliable integrations
  • Business case supported by real numbers after the first wave

Trade-offs

  • First migration is harder than it needs to be
  • Requires failure-rate data before starting

Risks

  • Team morale if the first migration is painful
  • Failure data being unavailable or unreliable

Decision 05

Leave synchronous user-triggered integrations on point-to-point

Roughly a third of the estate is a user pressing a button and waiting for a response.

Alternatives considered

  • Migrate everything for consistency
  • Migrate only asynchronous classes
  • Leave synchronous integrations unchanged

Reason

Putting a broker in a synchronous path adds latency and a failure mode to solve a resilience problem that path does not have. The user is present and will retry; that is a perfectly good error-handling strategy. Consistency for its own sake would make the user experience worse.

Benefits

  • No latency regression on interactive paths
  • Smaller migration scope
  • Effort concentrated where the incidents are

Trade-offs

  • Two architectural patterns coexist permanently
  • Requires documenting when to use which

Risks

  • Pattern confusion for new developers
  • Gradual erosion of the rule without an architecture review step
11

Implementation Approach

Data first, then one integration end to end, then waves. The first wave is chosen for pain, not for ease.

  1. 01Measure

    Weeks 1–4

    Inventory the integrations and classify them. Collect actual failure rates and per-application Graph consumption. Resist designing anything until this exists — the data reliably contradicts what the team expects.

    Milestones

    • Inventory complete
    • Classification agreed
    • Failure rates collected
    • Graph consumption baselined

    Success measures

    • Integrations inventoried
    • Failure rate per integration
    • Graph calls per application
  2. 02Foundation

    Weeks 4–10

    Stand up Service Bus, Event Grid, API Management and the observability pipeline. Define the event schema convention and the idempotency key rules. Nothing migrates yet, but the contracts are settled.

    Milestones

    • Infrastructure deployed
    • Schema convention published
    • Idempotency rules documented
    • Correlation tracing working end to end

    Success measures

    • Trace completeness across a synthetic transaction
  3. 03First integration

    Weeks 10–15

    Migrate the single worst offender end to end, including dead-letter handling and alerting. Deliberately over-invest here — this becomes the reference implementation every later wave copies, and shortcuts taken now get replicated twenty times.

    Milestones

    • One integration fully migrated
    • Dead-letter process exercised with a real failure
    • Runbook written
    • Reference implementation documented

    Success measures

    • Failure rate before and after
    • Mean time to detection
  4. 04Graph consolidation

    Weeks 12–20, overlapping

    Build the Graph access service and move consumers onto it one at a time, starting with the heaviest. Metering from day one so contention becomes visible immediately.

    Milestones

    • Access service live
    • Heaviest consumers migrated
    • Per-caller metering reporting

    Success measures

    • Throttling responses per week
    • Consumption attributed per integration
  5. 05Waves

    Quarters 2–3

    Remaining asynchronous integrations in descending order of failure rate. Each wave is small enough to complete inside a sprint boundary so progress stays visible and reversible.

    Milestones

    • Integrations migrated per wave
    • Incident volume tracked per wave

    Success measures

    • Integrations remaining
    • Incidents attributable to integration failure
  6. 06Operate

    Quarter 3 onward

    Ownership, runbooks and an architecture review step for new integrations so the estate does not quietly regrow its mesh. Anomaly detection on the telemetry moves in here, once there is enough history to learn from.

    Milestones

    • Owners assigned
    • Review step in place
    • Anomaly detection running

    Success measures

    • New integrations following the pattern
    • Mean time to detection sustained
12

Business Impact

What the design is intended to move, and the reasoning for each figure. Two of these are close to structural — they follow from the architecture rather than from optimism — and that is called out where it applies.

No system was built. These are design intents with stated assumptions, not observations.

Mean time to detect an integration failure

Hours to minutes

Projected

Follows structurally from dead-lettering plus alerting replacing an unwatched run history. Close to certain in direction; the magnitude depends on alert routing actually reaching someone awake, which is an operational question rather than an architectural one.

Duplicate-write incidents

0

Projected

A design property rather than a forecast. With a business idempotency key honoured by every consumer, redelivery cannot duplicate. It holds only as long as the key is genuinely unique per business event — a poorly chosen key silently reintroduces the problem.

Effort to add a consumer to an existing event

-70%

Estimated

Estimated from removing the producer-side change, its testing and its release. Assumes the event already exists and carries the data the new consumer needs; if it does not, this saving does not apply and a contract change is required.

Graph throttling responses

-80%

Projected

Projected from centralised backoff and consumption metering replacing independently-implemented retry. Depends on the batch windows actually being rescheduled once contention becomes visible — the architecture surfaces the problem, people still have to act on it.

Infrastructure cost

Increases

Illustrative

Stated as a direction rather than a number because it depends on message volume, tier and retention. Worth naming plainly: this architecture costs more to run than direct connections. The case rests on incident reduction and delivery speed, not on infrastructure savings, and pretending otherwise loses credibility in the first finance review.

13

Risks & Constraints

Six, including the two that argue against doing this at all.

RiskCategoryImpactProbabilityMitigation
The team lacks event-driven experience and builds a distributed monolithTechnicalHighMediumOver-invest in the first integration as a reference implementation, pair on the first two waves, and review event contracts as a group before they are published. If the skills gap is genuinely large, Option A is a more honest choice than a badly built Option B.
Eventual consistency surprises the businessOperationalMediumHighSay out loud, during design, which screens will be briefly stale and by how much. Most stakeholders accept a few seconds without complaint when told in advance and object strongly when they discover it in production.
Debugging becomes harder than the point-to-point estate it replacedOperationalMediumHighCorrelation identifiers and structured logging are foundation work, not a later increment. If tracing a synthetic transaction end to end does not work before the first migration, the migration is not ready to start.
The Graph access service becomes a bottleneck or a single point of failureTechnicalHighMediumDesign it for horizontal scale from the start, keep it stateless, and load-test it against combined peak before migrating the heaviest consumer onto it.
Infrastructure cost is not accepted after the design is agreedFinancialHighMediumModel the run cost during the measure phase and present it alongside incident cost. Do not lead the business case with savings that will not materialise.
The estate regrows a point-to-point mesh alongside the new layerOrganizationalMediumHighAn architecture review step for new integrations, and — more effective in practice — making the governed path genuinely quicker than writing a direct connection. Governance that is slower than the thing it replaces loses every time.
14

Security & Governance

Credentials

Managed identities between Azure components remove connection strings from configuration entirely. This is worth doing early, because retrofitting identity onto components already deployed with keys is tedious and tends to get deferred indefinitely.

Graph permissions

Consolidating Graph access into one service has a security benefit that is easy to overlook: individual integrations stop needing tenant-wide application permissions. Instead of a dozen registrations each holding broad Graph scopes, there is one registration with a reviewable permission set and a dozen callers authorised to use a narrow slice of it. That is a meaningful reduction in blast radius.

What travels in a message

Messages carry identifiers rather than sensitive values wherever the consumer can retrieve detail under its own authority. This keeps regulated data out of queues, which otherwise become an unplanned copy of it with their own retention and access questions.

Contracts and versioning

Event schemas are versioned artefacts. A breaking change publishes a new version alongside the old one; retiring the old version requires confirming nobody still consumes it. Editing a schema in place is how you take down consumers you had forgotten about.

Dead letters need an owner

A dead-letter queue with no owner is a folder of unprocessed business events accumulating quietly. It needs a named owner, an alert when it grows, and a documented replay procedure — which is safe precisely because idempotency keys make replay non-destructive.

15

Trade-offs

The honest ledger. The first two are the ones that get argued about.

Decoupling vs Traceability

A message crossing three hops is genuinely harder to follow than one flow you can open and read. Correlation identifiers recover most of that, but not all of it, and the team should expect debugging to feel worse before the observability work catches up.

Resilience vs Latency

Brokered messaging adds hops and therefore milliseconds to seconds. Fine for background work, wrong for a user waiting on a button — which is exactly why the synchronous class stays as it is.

Reliability vs Infrastructure cost

This estate costs more to run than direct connections did. The return is fewer incidents and faster delivery, and the case should be argued on those terms rather than on a saving that will not appear.

Centralised Graph access vs Team autonomy

Teams give up direct control of their Graph calls in exchange for backoff that works and contention that is visible. Reasonable trade, but it needs to be explained rather than imposed.

Two messaging services vs One thing to learn

Service Bus and Event Grid have different guarantees and different costs. Standardising on one would be simpler to teach and wrong for half the traffic.

Idempotency keys vs Consumer simplicity

Every consumer carries a processed-key store and a retention policy for it. Unglamorous work that eliminates an entire class of incident, which makes it the best-value complexity in the design.

16

Strategic Recommendation

A clear position, including where it does not apply.

Adopt Option B for the asynchronous and reactive classes only — roughly two thirds of the estate — and leave synchronous user-triggered integrations on direct connections permanently. Do not start until failure rates and Graph consumption have been measured.

Option A is a better answer than it looks and should be taken seriously: it addresses silent failure, which is the most painful symptom, at a fraction of the cost. It is the right call for an estate under roughly a dozen integrations or a team without event-driven experience. It fails on the two problems that actually compound — quadratic connection growth and duplicate writes — so it defers rather than resolves. Option C buys mature tooling but adds a platform to govern and duplicates capability already licensed in Azure; it makes sense when integration is a large enough portfolio to justify dedicated staffing, which this estate is not. Option B addresses the compounding problems directly, and its main weakness — operational complexity — is manageable if the observability work is treated as foundation rather than as a later phase. Scoping it to the classes that benefit avoids the most common failure of this pattern, which is migrating everything for the sake of consistency and making interactive paths slower.

Conditions

  • Failure rates and Graph consumption are measured before design — the migration order depends on data the team does not currently have
  • Correlation tracing works end to end before the first integration migrates
  • Run cost is modelled and accepted, framed against incident cost rather than as a saving
  • The team has, or is given, event-driven experience — otherwise Option A is the more honest recommendation
  • An architecture review step exists for new integrations before the first wave completes

Risks

  • Observability being deferred under schedule pressure, which removes the main benefit
  • Scope creeping to include synchronous integrations for consistency
  • The first integration being chosen for ease, producing a reference implementation with no measurable benefit

Next steps

  • Inventory and classify every integration by delivery guarantee and trigger type
  • Collect failure rates and per-application Graph consumption for a representative month
  • Model the run cost of Service Bus, Event Grid and API Management at observed volumes
  • Agree the event schema convention and idempotency key rules before any infrastructure is deployed
  • Pick the worst-performing asynchronous integration as the reference implementation
18

References

Public Microsoft documentation used for service behaviour, limits and patterns.

  1. Azure Service Bus messaging overview — Microsoft Learn · Documentation Source (opens in a new tab)

    Queues, topics, sessions and dead-lettering behaviour.

  2. Azure Event Grid overview — Microsoft Learn · Documentation Source (opens in a new tab)

    Delivery model underpinning the split between the two messaging services.

  3. Azure API Management key concepts — Microsoft Learn · Documentation Source (opens in a new tab)

    Front door, versioning and per-consumer rate limiting.

  4. Microsoft Graph throttling guidance — Microsoft Learn · Documentation Source (opens in a new tab)

    Per-tenant and per-application limits behind the Graph consolidation decision.

  5. Microsoft Graph change notifications overview — Microsoft Learn · Documentation Source (opens in a new tab)

    Replacing polling with subscriptions for reactive integrations.

  6. Transient fault handling best practices — Microsoft Learn · Documentation Source (opens in a new tab)

    Retry and backoff behaviour centralised in the access service.

  7. Publisher-Subscriber pattern — Microsoft Learn · Documentation Source (opens in a new tab)

    The decoupling pattern the design is built on.

  8. Azure Well-Architected Framework — Reliability — Microsoft Learn · Standard Source (opens in a new tab)

    Reliability principles applied to the messaging design.

17

Key Takeaways

01

Point-to-point is correct until it is not, and the crossover point does not announce itself. Connection count growing faster than system count is the signal to look for.

02

Silent failure, duplicate writes and throttling contention are one architectural problem wearing three costumes.

03

Idempotency keys are the highest-value, least interesting decision in the design. They cannot be retrofitted cheaply, so they belong in the first contract.

04

Service Bus and Event Grid are not interchangeable. Classify each event by whether losing it is acceptable, then pick.

05

Migrate by failure rate rather than by ease. Easy-first produces a migration nobody can point at when asking for the next round of funding.

06

Leave the synchronous paths alone. Consistency is not worth making a user wait longer.

07

This architecture costs more to run. Argue it on incidents and delivery speed, and the finance conversation stays honest.

08

Observability is foundation work. Deferred, it removes the main reason for doing any of this.

Working through a similar architecture or AI decision? I am happy to talk it through.

Get in touch
When Point-to-Point Integrations Stop Scaling: An Azure Event-Driven Approach | Rajiv Kumar