AZURE · REALTIME · ASYNCHRONOUS WORK
Event-driven,
but grounded in durable truth.
This is how we implemented a website RAG platform where chat had to feel immediate while ingestion could take minutes. The answer was not turning everything into an event: it was choosing two asynchronous channels and keeping one clear authority for state.
01 / THE ARCHITECTURE DECISION
Two event planes.
Two kinds of latency.
Conversation needs low-latency responses over persistent connections. Crawling needs buffering, retries, and independent scaling. One mechanism would have mixed incompatible guarantees.
Azure Web PubSub
Widget ↔ APIChat messages and update signals delivered with low latency.
Queue Storage + Functions
API → workerCrawls decoupled from the request, with retries and independent processing.
Azure SQL + REST
API → clientsQueryable state that can be reconciled after a disconnect or missed event.
DESIGN RULEWe did not start with “which event service should we use?” We started with “does this message notify, schedule work, or represent durable truth?”
02 / CONVERSATION PLANE
Web PubSub moves the answer.
The API keeps control.
The widget communicates over WebSocket, but it never executes business logic or reaches models and data directly. Web PubSub manages connections; the API validates context, orchestrates Azure OpenAI, persists the message, and returns a correlated response.
- 01NEGOTIATE
The API resolves the visitor and issues a short-lived connection URL.
- 02CREATE MESSAGE
The widget publishes an event with conversation, session, and message hash.
- 03ORCHESTRATE
The webhook reaches FastAPI, which runs retrieval and Azure OpenAI.
- 04COMMIT
The answer, sources, and cost are stored before delivery.
- 05CORRELATE
The API publishes to the originating client; the hash associates and deduplicates.
03 / INGESTION PLANE
The request starts it.
The queue finishes the work.
A crawl launches a browser, discovers links, transforms content, generates embeddings, and writes to several stores. Holding the HTTP request open would have coupled the operator to runtime duration and every downstream dependency.
- 01API
Creates GlobalCrawl and LocalCrawl as INPROGRESS.
- 02QUEUE
Publishes the URL and correlation identifiers.
- 03FUNCTION
Extracts, discovers, and reports through an internal callback.
- 04API
Stores Markdown, generates metadata, embeddings, and vectors.
- 05STATE
Recomputes status and publishes an admin notification.
Aggregate state is a function, not an event
- INPROGRESS
- When any active URL is still processing.
- FAILED
- When none is active and at least one failed.
- COMPLETED
- Only when every active URL completed.
04 / REAL GUARANTEES
Design for repetition.
Reconcile what you separate.
Queues and realtime channels improve decoupling and responsiveness, but introduce duplicates, delays, partial failures, and intermediate states. Reliability appears when those cases are part of the contract.
IDEMPOTENCY
URL normalization and existence checks reduce duplicates. A recrawl reuses the existing identity. Callbacks must tolerate repetition.
CORRELATION
Request ID, message hash, connection, conversation, global crawl, local crawl, and dequeue count join a distributed operation.
BOUNDED RETRIES
The Function retries transient failures; at the limit, it reports FAILED instead of leaving work pending forever.
RECONCILIATION
SQL is authoritative, but Blob and the vector index can drift. Metrics and repair jobs must detect that mismatch.
HONEST SEMANTICSThe system does not promise exactly-once. It accepts repeated delivery and makes effects safe under at-least-once processing.
05 / FAILURE MODES
The hard part starts
after the happy path.
The architecture earns its value in what it does when a channel, worker, or external write fails halfway through the flow.
A notification is missed
The admin refetches REST; the event accelerates the UI but does not define state.
The worker fails
The queue enables retries. State ends as FAILED when the budget is exhausted.
SQL, Blob, or vectors diverge
The system does not claim COMPLETED while a required artifact is missing; residual drift is reconciled.
An active crawl is deleted
Soft deletion does not magically cancel a running Function. Run IDs, cancellation state, and cooperative polling are required.
06 / THE PLAYBOOK
Six questions before
choosing the broker.
The product defines the guarantees; Azure implements the channel. This order prevents one tool from being used for problems that only look alike on a diagram.
- 01
Does the message announce a fact or assign work?
- 02
Which component owns the source of truth?
- 03
What happens if the message arrives twice?
- 04
Which identifier correlates the whole journey?
- 05
When do retries stop?
- 06
How is partial state detected and repaired?
Events decouple.
State explains what happened.
Azure Web PubSub made conversation immediate. Queue Storage and Functions isolated heavy work. Azure SQL kept a queryable history. The solution worked because every piece had a distinct responsibility and guarantees were designed around failure, not only flow.
07 / REFERENCES
Sources and context
The implementation is a sanitized synthesis of the architecture document supplied for this article. External references document the Azure services and patterns.