Document 6 min read

Architecture One-Pager

Solution Architecture v1.0 · Microsoft Azure · Integration Platform Architecture · 2026-10 · 19 views · 12 architecture decision records

Discord Bot Platform · Solution Architecture v1.0 · Microsoft Azure · Integration Platform Architecture · 2026-10 · 19 views · 12 architecture decision records

Bots are untrusted consumers on the far side of a one-way boundary: entitlement is enforced before an event is produced, the shard is an address you compute, and every promise states what it loses.

A chat service with 150 million users lets anyone register code that reacts to messages. Some bots are slow. Some are offline for days. A few are hostile. One, at any moment, is a viral slash command running on a serverless function with a cold start — and a person is staring at a spinner waiting for it. In the obvious architecture each of these problems leaks back into the chat service: a slow bot slows a message, a reconnecting fleet takes down the registry, and a revoked bot keeps reading for an hour.

The chat service commits and emits an event, and its involvement ends. Fan-out consumes events partitioned by server, filters them by the bot's intents and the server's permissions before anything is serialised, and routes each to a shard that is simply arithmetic on the server identifier. Gateway pods hold the sockets, with a bounded buffer per session and a 120-second resume window; a bot that reads too slowly is closed resumably, not allowed to grow memory. Slash commands arrive by signed HTTPS or the socket and carry a three-second acknowledgement the platform enforces, with deferral to fifteen minutes. REST actions pass a per-route-bucket limiter whose headers tell the client exactly what to do. Installations belong to the server, and revocation pushes to every node with a ten-second lease as the backstop. Reconnect storms are smeared by server-directed jitter and an identify throttle.

What it is, and what it is not

  • Entitlement enforced at the source — not send-everything-and-filter-in-the-client, which leaks data and spends bandwidth.
  • Shard as arithmetic — not a routing table that becomes a hot, replicated dependency.
  • A published loss boundary at 120 seconds — not an exactly-once claim the platform cannot keep.
  • A three-second acknowledgement — not unbounded waiting on a stranger's endpoint.
  • Server-owned installations — not grants tied to developer accounts that vanish.
  • State classed by how it may be lost — not one strongly consistent store for everything.
  • Topological containment of egress — not an SSRF validator as the only defence.

The decisions that are the architecture

  1. The chat service never waits on a bot (ADR-01) — Events leave over a one-way stream; bot actions return through a separate API edge.
  2. Filter before serialising, route by arithmetic (ADR-02) — Nothing unentitled is produced, and shard placement needs no lookup.
  3. Three seconds, then a visible failure (ADR-03) — The wait on a stranger is bounded and the expiry is shown to the user.
  4. A loss boundary that is published (ADR-04) — Ordered replay for 120 s, explicit loss after, bounded buffers throughout.
  5. Partition by server (ADR-05) — A hot server is one partition, not many copies.
  6. The server owns the grant (ADR-06) — Permissions are evaluated on every call against current roles.
  7. Directed, throttled reconnects (ADR-07) — The recovery path is cheaper than the failure path.
  8. Revocation has a deadline (ADR-08) — Push plus a ten-second lease.
  9. Limits that can be read (ADR-09) — Bucketed, with headers, escalating to bans only for offenders.
  10. Egress contained by topology (ADR-11) — A separate zone with a published range.

Why this should still be right in ten years

A bot platform outlives its first generation of bots, because developers write against the protocol and never rewrite it. These are the properties that should survive a change of scale, of cloud and of staff.

  • The trust boundary depends on no technology. ADR-01 survives replacing Event Hubs, AKS and Azure. What would erode it is an exception for a first-party bot that blocks sending a message.
  • The shard formula is public API. Changing it breaks every deployed bot, which is exactly why it is arithmetic and documented, not infrastructure.
  • Explicit loss boundaries age well. Numbers change; the stance that every promise states what it drops does not.
  • Ownership follows consequence. The server bears the risk of a bot, so the server holds the grant. That rule is independent of scale.

Non-functional targets

Every number here is a stated assumption from the requirement, chosen to be argued with. The right-hand column names the view where the mechanism that meets it is drawn.

Quality Target How it is met View
Gateway delivery latency p50 ≤ 120 ms, p99 ≤ 800 ms commit to socket One filter and one shard hop; no registry call per event, because entitlements are leased. 12
Gateway availability ≥ 99.95 % monthly Per-shard session continuity; node loss is a resume, not an outage. 13
Interaction acknowledgement 3 s hard; POST ≤ 300 ms p99 after click Isolated egress, one retry in-window, enforced timer. 11
Event throughput 400,000 events/s, 3× burst for 60 s Server-partitioned log and arithmetic routing scale horizontally. 12
REST throughput 90,000 requests/s, 4× burst Stateless API pods and regional bucket counters. 14
Revocation ≤ 10 s effective Push invalidation with a 10 s lease backstop. 19
Region loss RTO 5 min new sessions; registry RPO 0 Registry replicates; sessions are rebuilt by reconnecting. 14
Reconnect storm 500,000 sessions in 10 min, registry p99 ≤ 50 ms Server-directed jitter and identify throttle. 13

Scope

In scope

  • Gateway sessions, sharding, intents, resume.
  • Interactions with signing, acknowledgement and deferral.
  • REST with route-bucket limits and permission evaluation.
  • Installation, grants, tokens and revocation.
  • Developer-facing health and test tooling.
  • Egress isolation for bot-supplied URLs.

Explicitly out of scope

  • Message storage and the chat service itself.
  • Voice media.
  • Bot hosting and runtimes.
  • A paid marketplace.
  • User-facing clients.
  • Abuse model training.

What a four-week prototype should prove

Three claims are cheap to test and expensive to be wrong about.

  1. Reconnect storm: kill a node holding 40,000 sessions and measure registry p99 and time-to-resume with and without the identify throttle.
  2. Slow consumer: one bot reading at 1 % of event rate, measuring pod memory and the effect on neighbouring sessions at the buffer bound.
  3. Revocation: revoke a grant under a registry brownout and measure the worst-case time until the session stops receiving events.
  • A gateway node holding 40,000 sessions is killed during peak: every session resumes or re-identifies inside 10 minutes and registry p99 stays under 50 ms.
  • One bot stops reading while its server posts 5,000 messages per second: its session closes resumably at the buffer bound, and no neighbouring session on the pod sees added latency.
  • An administrator revokes a bot during a registry brownout: the bot stops receiving events inside 10 seconds, or the scenario records exactly how long it took.

Open risks, carried rather than hidden

Risk If it lands Response
The 120-second window is too short or too long Too short and ordinary flaky networks force identifies; too long and memory outgrows budget. Instrument reconnect-time distribution before fixing the number; revisit quarterly.
A first-party exception erodes the trust boundary A bot that must block a message puts a stranger on the write path. Make such a feature a separate, explicitly synchronous product with its own SLO.
Serverless bots miss 3 seconds at scale A viral command shows failures the platform is blamed for. Deferral guidance, keep-warm recommendations and per-application ack-rate visibility in the portal.

The reasoning behind every component and technology choice is in the Architecture Decision Record: 12 records across 11 areas, each with the alternatives that lost and what the choice costs.