Three ways two-way sync goes wrong
Keeping two calendars in step sounds simple until both sides can write. Then it fails in three recognizable ways: duplicates, loops and floods of notifications. We have dealt with all three, on Microsoft Graph, at enterprise scale.
Breaking the loop
A loop starts when our own write comes back as news. We write an event to Outlook, Graph fires a webhook for that write, and a naive integration treats the webhook as a fresh change and writes again.
The fix is to recognize an echo. We compare strict change keys and ETags to tell a real change from the reflection of our own, and we keep short-lived idempotency values in Redis so the same change is never applied twice. The same mechanism keeps duplicates out.
Waiting out the storm
Graph is generous with notifications. A single simple edit can arrive as five or six webhook calls, and attendee changes or bulk edits multiply that. Reacting to each one means doing the same work six times and notifying people six times.
So notifications are not processed as they arrive. They are collected in a bucket, and the bucket is processed once the storm has ended.
Rate limits, and the one time we hit one
All Graph work goes through queues, with tokens cached per tenant. In normal operation we have not run into Graph throttling.
The one time Graph did limit us, request volume was not the cause. The problem was on the outbound side of our own network: SNAT ports. Raising the allocated outbound ports fixed it. It is a useful reminder that a rate-limit error is not always about your request rate.
Subscriptions that renew themselves
Graph webhook subscriptions expire, and an expired subscription fails quietly: changes simply stop arriving. Cron jobs renew every subscription a day before it expires and retry each failure. If a renewal keeps failing, an alert tells us.
Where people already work
The Outlook add-in, the Teams app and the Azure AD attribute sync share one idea: nobody should have to open a second system. If a team lives in Teams, the booking happens in Teams. If they live in Outlook, it happens in Outlook. User attributes follow Azure AD, so people are not maintained in two places.
Never finished
The integration has been in production for several years, with monitoring and alerts on the failure modes that recur. It is not a project that ended. There is always a small improvement to make, and clear ownership of the whole surface means it gets made.