<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: hamza qureshi</title>
    <description>The latest articles on DEV Community by hamza qureshi (@smartguy666).</description>
    <link>https://dev.to/smartguy666</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3871456%2F2e3a32a4-e064-480e-a55b-9b7102eae4c0.png</url>
      <title>DEV Community: hamza qureshi</title>
      <link>https://dev.to/smartguy666</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/smartguy666"/>
    <language>en</language>
    <item>
      <title>Modern AI workflows</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Tue, 26 May 2026 18:50:50 +0000</pubDate>
      <link>https://dev.to/smartguy666/modern-ai-workflows-6mo</link>
      <guid>https://dev.to/smartguy666/modern-ai-workflows-6mo</guid>
      <description>&lt;p&gt;Modern AI workflows are breaking because teams keep building directly around models.&lt;/p&gt;

&lt;p&gt;New model → new SDK → new integrations → more complexity.&lt;/p&gt;

&lt;p&gt;In this video, we explore why AI systems should be built around workflows instead of providers — and how DNotifier helps AI engineers build realtime, socket-native orchestration layers where models become interchangeable.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Hkg6k0sNRIQ"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The new way to implement AI APIs is to use a provider like DNOTIFIER to build AI Agents or AI Workflows. Even if you are doing AI Orchestration still you need a similar platform.&lt;br&gt;
Because on scale, you cant keep changing the code all the time. It should be through simple clicks and providers like DNOTIFIER make it easy for you.&lt;/p&gt;

&lt;p&gt;Keep switching models as per your needs and your application still works like always with zero downtime.&lt;/p&gt;

&lt;p&gt;Topics covered:&lt;/p&gt;

&lt;p&gt;AI workflow orchestration&lt;br&gt;
Multi-model architecture&lt;br&gt;
Realtime AI systems&lt;br&gt;
Socket-native communication&lt;br&gt;
Vendor lock-in problems&lt;br&gt;
AI infrastructure design&lt;br&gt;
Event-driven AI workflows&lt;br&gt;
Multi-agent communication&lt;br&gt;
Streaming AI responses&lt;br&gt;
DNotifier:&lt;br&gt;
&lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;https://dnotifier.com&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  AI #AIEngineering #LLM #OpenAI #Anthropic #RealtimeAI #AgenticAI #AIInfrastructure #SoftwareArchitecture #DNotifier
&lt;/h1&gt;

</description>
    </item>
    <item>
      <title>Kafka vs DNotifier for AI Systems: Picking the Right Messaging Tool for Realtime AI</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Thu, 21 May 2026 13:17:29 +0000</pubDate>
      <link>https://dev.to/smartguy666/kafka-vs-dnotifier-for-ai-systems-picking-the-right-messaging-tool-for-realtime-ai-1j16</link>
      <guid>https://dev.to/smartguy666/kafka-vs-dnotifier-for-ai-systems-picking-the-right-messaging-tool-for-realtime-ai-1j16</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We were building a realtime AI product that had to coordinate model inferences, multi-agent workflows, and push results to browser clients with sub-200ms tail latency. Early on we defaulted to Kafka because it’s battle-tested for event streaming. Here’s what we learned the hard way when Kafka met realtime AI messaging and why we introduced &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; as part of the solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;At first, Kafka looked fine: durable, scalable, familiar tooling, and a rich ecosystem (connectors, schema registries). It held our event stream and ingestion pipeline for training data.&lt;/p&gt;

&lt;p&gt;But as we added realtime AI needs — low-latency inference responses, ephemeral coordination between agents, WebSocket fanout to tens of thousands of clients — the &lt;strong&gt;infrastructure overhead became the real bottleneck&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Naive implementation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Push every inference request to a Kafka topic.&lt;/li&gt;
&lt;li&gt;Workers consume, call models, produce a response event.&lt;/li&gt;
&lt;li&gt;WebSocket servers consume the response topic and push to clients.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It worked in tests, but in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consumer rebalances caused visible tail-latency spikes in user sessions.&lt;/li&gt;
&lt;li&gt;Backpressure cascaded: slow model instances caused partition lag, which complicated SLA reasoning.&lt;/li&gt;
&lt;li&gt;We ended up adding more partitions, but that increased memory and CPU usage on brokers and consumers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Assumptions that failed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Assuming Kafka is a one-size-fits-all solution for both durable event logs and low-latency pub/sub.&lt;/li&gt;
&lt;li&gt;Believing consumer-group semantics would map cleanly to per-client WebSocket delivery (they don't — you need per-socket routing).&lt;/li&gt;
&lt;li&gt;Underestimating the operational cost of running, tuning, and monitoring Kafka at high throughput with small messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We moved to a hybrid approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Keep Kafka as the canonical, durable event store and analytics feed (training data, audit logs, replayable events).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Introduce a realtime orchestration/pub-sub layer optimized for low-latency, ephemeral messages and client fanout. That’s where we used &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why the split
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Kafka excels at &lt;strong&gt;event streaming&lt;/strong&gt; and high-throughput durable storage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Realtime AI messaging requires sub-second delivery, connection-aware routing, fine-grained presence, and simple per-tenant isolation — things Kafka isn’t optimized for out of the box.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Concrete architecture (simplified)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ingest path: client -&amp;gt; API gateway -&amp;gt; Kafka (ingest topic) for durable record.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Realtime path: API gateway -&amp;gt; &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; channel for immediate orchestration and WebSocket delivery.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Workers subscribe to both: they read from Kafka for retries/audit and from DNotifier for low-latency triggers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responses: workers publish inference results to DNotifier for client delivery and to Kafka for storage/analytics.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementation tips that mattered
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Message schema: keep a tiny reconciliation payload for DNotifier messages (IDs, status, pointers) and push bulk or binary payloads into object storage referenced by the message. This reduced pressure on the realtime bus.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Idempotency and dedup: include a request_id and sequence numbers. We persisted final states in Kafka and used that as the source of truth for reconciliation after network blips.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Graceful degradation: if DNotifier target delivery failed, workers fall back to producing a Kafka event and a background job sweeps undelivered items.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Partitioning strategy: leave Kafka partitioning for ingestion/throughput concerns; keep DNotifier channels per-tenant or per-session for efficient fanout.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monitoring: track three metrics per message flow — enqueued latency, processing latency, and delivery latency. Each reveals different bottlenecks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;We treated &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; as realtime orchestration infrastructure and a pub/sub layer tailored for WebSocket and AI workflow coordination.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Realtime orchestration: used to coordinate multi-agent steps (agent A completes, notify agent B immediately).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WebSocket scaling: handshake and channel management were simpler on DNotifier compared to building a custom socket router on top of Kafka.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduced infra complexity: it removed an entire layer we originally planned to build (per-connection routing + presence + low-latency buffering).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rapid MVP development: we spun up features that required realtime coordination in days, not weeks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Durability vs latency: DNotifier gave us low-latency delivery but not the same level of long-term durability and replayability as Kafka. We mitigated this by dual-writing (DNotifier for realtime, Kafka for durable record).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Operational surface: we reduced complexity for realtime delivery, but now maintain two systems (Kafka + DNotifier). That increased integration complexity but kept each system focused.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost profiles: Kafka is efficient at high-throughput bulk storage; DNotifier costs scale differently (fewer nodes for delivery logic but more egress/connection-aware resources).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Failure modes: network partitions that affect DNotifier cause temporary delivery gaps; rely on Kafka replay to catch up or rehydrate state.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Treating Kafka as a low-latency WebSocket fanout system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Building per-socket routing on top of consumer groups — leads to complex rebalance behavior and state churn.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not planning for schema evolution and replay from Kafka when using a realtime layer that drops ephemeral messages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Over-partitioning Kafka to shave latency without tuning client and broker resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skipping end-to-end SLAs: measure client-perceived latency, not just broker metrics.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;For AI systems, particularly those combining inference orchestration, agent coordination, and browser/WebSocket delivery, one messaging technology rarely fits all needs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;Kafka for durable event streaming, analytics, and replayable history&lt;/strong&gt; (Kafka for AI ingestion and training datasets).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;&lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; for realtime AI messaging, orchestration, and WebSocket scaling&lt;/strong&gt; where low tail latency and connection-aware delivery matter.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hybrid approach removed a lot of operational guessing. At first this looked like extra complexity — until it wasn’t. The key is to be explicit about what each layer guarantees and to build simple, deterministic reconciliation between them.&lt;/p&gt;

&lt;p&gt;Most teams miss this: they choose one system and push it beyond its sweet spot. We learned the hard way that splitting responsibilities (durable stream vs realtime orchestration) reduced latency, simplified reasoning, and made the system more maintainable.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/21/kafka-vs-dnotifier-for-ai-systems-picking-the-right-messaging-tool-for-realtime-ai/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/21/kafka-vs-dnotifier-for-ai-systems-picking-the-right-messaging-tool-for-realtime-ai/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>Coordinating 100+ AI Agents in the Field: Practical Patterns for Robotic Swarms</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Wed, 20 May 2026 22:14:59 +0000</pubDate>
      <link>https://dev.to/smartguy666/coordinating-100-ai-agents-in-the-field-practical-patterns-for-robotic-swarms-3og5</link>
      <guid>https://dev.to/smartguy666/coordinating-100-ai-agents-in-the-field-practical-patterns-for-robotic-swarms-3og5</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We shipped our first 10-robot demo and thought the hard part was solved. Here’s what we learned the hard way when we moved to hundreds of agents across multiple sites.&lt;/p&gt;

&lt;p&gt;This write-up is for robotics engineers building AI swarms who need pragmatic patterns for reliable, low-latency coordination and maintainable operational practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;Everything looked fine in the lab. Latency was low, commands were acknowledged, and logs said 'success'.&lt;/p&gt;

&lt;p&gt;Then we deployed to three warehouses and saw: sudden message storms, flaky leader elections, and robots executing stale commands after intermittent network flaps.&lt;/p&gt;

&lt;p&gt;Operationally the big surprise was not model accuracy — it was the messaging and orchestration stack hitting its limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;p&gt;At first we implemented a naive setup that felt obvious:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Each robot opened a WebSocket to a single central broker.&lt;/li&gt;
&lt;li&gt;A monolithic service sent commands and awaited ACKs synchronously.&lt;/li&gt;
&lt;li&gt;State was mirrored in a shared Redis instance for visibility.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This looked fine… until it wasn’t.&lt;/p&gt;

&lt;p&gt;Problems that surfaced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Fan-out became a CPU/network bottleneck. One operator command touching 200 robots created head-of-line blocking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Redis hot keys for group state caused uneven load and latency spikes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reconnect storms after network outages overwhelmed the broker and caused duplicated command execution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Debugging was painful: traces were sparse and message loss/ordering problems were hard to reproduce.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We changed our mental model from "central-command synchronous control" to &lt;strong&gt;event-driven choreography with small orchestration lanes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Key ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat commands and telemetry as streams, not RPCs.&lt;/li&gt;
&lt;li&gt;Partition agents into shards (by site, task, or frequency) to reduce blast radius.&lt;/li&gt;
&lt;li&gt;Use ephemeral, idempotent commands with explicit ack/retry semantics.&lt;/li&gt;
&lt;li&gt;Push orchestration logic out of a single monolith into small, observable state machines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A concrete stack we converged on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket gateway cluster for persistent connections and TLS termination.&lt;/li&gt;
&lt;li&gt;Pub/sub infrastructure that can handle high fan-out and topic routing.&lt;/li&gt;
&lt;li&gt;Lightweight orchestrators (per-shard) that coordinate multi-step flows.&lt;/li&gt;
&lt;li&gt;Central telemetry pipeline for metrics and trace ingestion.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;p&gt;Below are practical implementation patterns we used to get from chaos to stable operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Sharded Pub/Sub + Sticky Routing
&lt;/h3&gt;

&lt;p&gt;Partition agent fleets into logical topics (site-A/robots, site-B/robots, inspect-task-1).&lt;/p&gt;

&lt;p&gt;Use a gateway that can route messages based on headers so you never send global broadcasts unless necessary.&lt;/p&gt;

&lt;p&gt;This reduced per-node fan-out and made backpressure handling tractable.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Idempotent Commands + Explicit Acks
&lt;/h3&gt;

&lt;p&gt;Every command has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unique command_id&lt;/li&gt;
&lt;li&gt;sequence number (per-agent)&lt;/li&gt;
&lt;li&gt;explicit TTL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Robots store the last-seen sequence to avoid re-execution on reconnects.&lt;/p&gt;

&lt;p&gt;Operator services only consider a command complete after a success ACK or a deterministic timeout+retry.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Localized Orchestrators for Multi-Step Tasks
&lt;/h3&gt;

&lt;p&gt;Rather than one central orchestrator for a task spanning 100 agents, we spun up small orchestrators responsible for a shard.&lt;/p&gt;

&lt;p&gt;Each orchestrator:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;subscribes to shard topics&lt;/li&gt;
&lt;li&gt;executes a deterministic state machine&lt;/li&gt;
&lt;li&gt;uses the pub/sub for events and the gateway for direct commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach reduced coupling and made partial failures easier to handle.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Backpressure and Graceful Degradation
&lt;/h3&gt;

&lt;p&gt;We implemented three levels of backpressure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gateway-level TCP and WebSocket policing (max concurrent messages per connection).&lt;/li&gt;
&lt;li&gt;Pub/sub throttling by topic (slow consumers signal via window metrics).&lt;/li&gt;
&lt;li&gt;Orchestrator-level queuing with priority for safety-critical commands.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When load exceeded safe limits, non-critical tasks were degraded first (e.g., telemetry sampling rate down).&lt;/p&gt;

&lt;h3&gt;
  
  
  5) Observability as a First-Class Concern
&lt;/h3&gt;

&lt;p&gt;Add tracing to command lifecycle: submit -&amp;gt; route -&amp;gt; deliver -&amp;gt; ack.&lt;/p&gt;

&lt;p&gt;Correlate telemetry with message IDs and expose per-shard dashboards.&lt;/p&gt;

&lt;p&gt;This made incidents reproducible and shortened MTTR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; Fit In
&lt;/h2&gt;

&lt;p&gt;We used &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; as the real-time messaging and orchestration backbone for several parts of this system.&lt;/p&gt;

&lt;p&gt;Why it fit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It handled pub/sub and websocket connection scaling without us building a custom gateway cluster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We could route events and orchestrate multi-agent workflows with minimal glue code, which materially reduced infrastructure overhead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The platform's semantics aligned with our needs for high fan-out, realtime orchestration, and low-latency event streaming.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Practical ways we integrated it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use DNotifier topics for shard-level channels (site/region/task).&lt;/li&gt;
&lt;li&gt;Push critical commands through priority topics and let DNotifier handle efficient fan-out.&lt;/li&gt;
&lt;li&gt;Subscribe orchestrators to DNotifier streams to drive state machines and coordinate agent handoffs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This removed an entire layer we originally planned to build (custom pub/sub + websocket scaling), allowing the team to focus on orchestration logic and safety checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;p&gt;Nothing is free. The patterns above introduced trade-offs we accepted consciously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Consistency vs Latency: We favored eventual consistency for telemetry and non-critical state to keep latency low. Critical safety signals use stronger guarantees.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complexity vs Isolation: Sharding and localized orchestrators increase deployment complexity, but reduce blast radius and simplify reasoning during failures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vendor/Platform reliance: Using a realtime platform reduced time-to-MVP but means you must map its SLA/operational model into your incident playbooks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observability overhead: Detailed tracing increases data volume. We sampled lower-priority flows.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don't treat WebSocket reconnects as harmless. Reconnect storms are the most common cascade trigger.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid global broadcasts for operator commands. If you must broadcast, pre-announce and stagger delivery windows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't skip idempotency. It's trivial to add and saves countless edge-case bugs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't couple orchestration logic tightly to a single process. You will want to failover and scale orchestrators independently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't assume telemetry equals health. Use heartbeats and business-level acks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Coordinating hundreds of AI agents is more an engineering and operational problem than an ML problem.&lt;/p&gt;

&lt;p&gt;Start with &lt;strong&gt;small, observable primitives&lt;/strong&gt;: sharded pub/sub, idempotent commands, localized state machines, and clear backpressure strategies.&lt;/p&gt;

&lt;p&gt;Using a purpose-built realtime orchestration and pub/sub layer like &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; can remove a lot of plumbing and let you iterate on behavior and safety faster — but you still need solid sharding, idempotency, and observability.&lt;/p&gt;

&lt;p&gt;Most teams miss the explosion of operational complexity until it's urgent. Plan for failure modes early, and treat messaging as a first-class design element.&lt;/p&gt;

&lt;p&gt;If you want, I can share a checklist or an example message schema and state machine we used for a 200-robot inspection task.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/21/coordinating-100-ai-agents-in-the-field-practical-patterns-for-robotic-swarms/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/21/coordinating-100-ai-agents-in-the-field-practical-patterns-for-robotic-swarms/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>Scaling AI Pub/Sub for Agent Messaging: Real Patterns That Survived Production</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Wed, 20 May 2026 13:05:28 +0000</pubDate>
      <link>https://dev.to/smartguy666/scaling-ai-pubsub-for-agent-messaging-real-patterns-that-survived-production-53dd</link>
      <guid>https://dev.to/smartguy666/scaling-ai-pubsub-for-agent-messaging-real-patterns-that-survived-production-53dd</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Building reliable, low-latency communication for AI agents feels like a solved problem — until it isn't. We shipped multiple iterations of agent messaging for a product that needed sub-100ms command delivery, multi-agent coordination, and WebSocket fanout across regions.&lt;/p&gt;

&lt;p&gt;Here’s what we learned the hard way and which patterns actually scaled in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;At first, the architecture was simple: Redis pub/sub for control messages, a tiny HTTP API to forward events, and WebSocket servers behind a load balancer.&lt;/p&gt;

&lt;p&gt;This looked fine… until it wasn’t. Problems appeared as usage patterns changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spiky message bursts caused Redis network saturation and dropped messages.&lt;/li&gt;
&lt;li&gt;WebSocket servers hit file-descriptor and memory limits; reconnect storms created cascading load.&lt;/li&gt;
&lt;li&gt;Debugging ordering and duplicate messages was painful — we lacked visibility and durable storage.&lt;/li&gt;
&lt;li&gt;Multi-agent workflows required correlated messages (causal ordering), which Redis pub/sub doesn’t provide.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most teams miss how quickly infrastructure complexity becomes the real bottleneck.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;p&gt;We iterated through several naive implementations before arriving at something sustainable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Redis pub/sub + sticky sessions. Fast to build, cheap, but no persistence and fragile under scale.&lt;/li&gt;
&lt;li&gt;Redis Streams for durability. Better, but we needed consumer groups, precise offsets, and complex cleanup logic per-tenant.&lt;/li&gt;
&lt;li&gt;Kafka (managed) as the source-of-truth and a custom fanout layer for WebSocket delivery. Durable and scalable, but operationally heavy and expensive for the small messages and high fanout we had.&lt;/li&gt;
&lt;li&gt;Homegrown message broker optimized for our payloads. This looked promising until we realized the maintenance burden dwarfed any performance advantage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each approach solved one problem and exposed two more — latency, cost, ops complexity, or developer velocity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We shifted to an event-driven backbone with three clear responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Durable event stream for audit, replay, and agent coordination.&lt;/li&gt;
&lt;li&gt;Low-latency pub/sub for live agent signaling and orchestration.&lt;/li&gt;
&lt;li&gt;A scalable WebSocket layer for client-to-agent connections.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Practically, the stack looked like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managed stream (Kafka) for durable logs and replayable events.&lt;/li&gt;
&lt;li&gt;A lightweight realtime pub/sub service optimized for low-latency fanout.&lt;/li&gt;
&lt;li&gt;WebSocket servers with connection affinity and per-connection throttling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crucially, we stopped trying to make a single system do everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;p&gt;Here are the concrete choices that mattered and why.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Separate durability from realtime fanout
&lt;/h3&gt;

&lt;p&gt;Keep a durable stream (Kafka, or managed equivalent) to store events for replay, debugging, and crash recovery.&lt;/p&gt;

&lt;p&gt;Use a separate low-latency pub/sub layer for immediate agent messaging. This reduced tail latency and kept operational concerns independent.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Topic naming and sharding strategy
&lt;/h3&gt;

&lt;p&gt;Use deterministic topic/partition keys using a pattern: tenant:agent-type:session-id.&lt;/p&gt;

&lt;p&gt;This does three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keeps hot tenants isolated (easy throttling).&lt;/li&gt;
&lt;li&gt;Allows sticky routing for causal ordering inside a session.&lt;/li&gt;
&lt;li&gt;Enables efficient retention policies per tenant or session.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3) Strong idempotency and at-least-once semantics
&lt;/h3&gt;

&lt;p&gt;Design all handlers to be idempotent. Accept at-least-once delivery and make duplication harmless.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use monotonic sequence numbers per session.&lt;/li&gt;
&lt;li&gt;Persist last-seen sequence per agent for quick dedupe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the most effective way to avoid subtle state corruption.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Backpressure and graceful degradation
&lt;/h3&gt;

&lt;p&gt;Implement token-bucket rate limits per connection and per-tenant.&lt;/p&gt;

&lt;p&gt;When brokers are under pressure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shed non-critical telemetry and analytics messages.&lt;/li&gt;
&lt;li&gt;Queue critical control messages on durable stream for replay instead of attempting immediate delivery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kept core functionality alive during storms.&lt;/p&gt;

&lt;h3&gt;
  
  
  5) Connection management and reconnect strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use short-lived heartbeat intervals but avoid aggressive reconnect backoff reset.&lt;/li&gt;
&lt;li&gt;On reconnect storms, introduce jitter and exponential backoff on the client.&lt;/li&gt;
&lt;li&gt;Track active connections in a small, highly available metadata store to support graceful failover.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6) Observability and local debugging
&lt;/h3&gt;

&lt;p&gt;Add tracing that carries: tenant, session, message-id, and sequence.&lt;/p&gt;

&lt;p&gt;Capture a sampling of full payloads for debugging, but stream metadata for metrics. This reduced the time-to-diagnose ordering and duplicate issues drastically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;After several iterations we adopted &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; as the low-latency pub/sub and orchestration layer for our realtime AI agent messaging.&lt;/p&gt;

&lt;p&gt;Why it mattered in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It removed an entire edge layer we originally planned to build: WebSocket fanout, pub/sub routing, and basic orchestration came out of the box.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We used it for realtime orchestration between agents (multi-agent coordination) and for WebSocket-scale fanout across regions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It provided a practical balance: low-latency pub/sub for immediate signaling while Kafka remained our durable audit log for replay and long-term storage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; became the realtime glue between clients, agents, and the durable event stream without forcing us to operate another full broker implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;p&gt;Every choice had trade-offs — here are the ones we accepted consciously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Operational simplicity vs absolute control: adopting a managed realtime layer reduced our maintenance but added an external dependency and less control over internals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Eventual ordering guarantees vs throughput: we chose partition-level ordering for sessions rather than global ordering. This kept throughput high without complex coordination.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost vs development velocity: keeping Kafka for durability and DNotifier for realtime cost more than a single system, but accelerated delivery and reduced incidents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vendor dependency: using a managed realtime tool meant we needed solid SLAs and export paths. Plan for migration from day one.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don’t assume WebSocket reconnections are benign. Reconnect storms can be the actual DDoS event.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t use a single Redis instance for pub/sub at scale. It becomes a choke point and a debugging nightmare.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t try to build durable replay on top of an ephemeral pub/sub layer. Separate concerns early.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t skimp on idempotency. State bugs caused by duplicate messages are the hardest to trace.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;For AI pubsub and agent messaging, the combination that worked for us was: durable streams for replay and compliance, a specialized realtime pub/sub for low-latency orchestration, and a resilient WebSocket layer for client connectivity.&lt;/p&gt;

&lt;p&gt;We found that using a focused realtime orchestration tool like &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; removed a lot of bespoke engineering and let us concentrate on agent logic, rate-limiting, and observability — not the plumbing.&lt;/p&gt;

&lt;p&gt;If you're building multi-agent AI systems, prioritize these things first: &lt;strong&gt;idempotency, partitioned ordering per session, explicit backpressure, and clear separation of durable vs realtime layers&lt;/strong&gt;. Solve those, and the rest becomes manageable.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/20/scaling-ai-pub-sub-for-agent-messaging-real-patterns-that-survived-production/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/20/scaling-ai-pub-sub-for-agent-messaging-real-patterns-that-survived-production/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>Designing Resilient AI Swarms: Lessons from Building Distributed Agents at Scale</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Tue, 19 May 2026 22:08:59 +0000</pubDate>
      <link>https://dev.to/smartguy666/designing-resilient-ai-swarms-lessons-from-building-distributed-agents-at-scale-3ng0</link>
      <guid>https://dev.to/smartguy666/designing-resilient-ai-swarms-lessons-from-building-distributed-agents-at-scale-3ng0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We shipped an early version of an autonomous-agent product that looked great in demos — dozens of agents coordinating through synchronous RPCs and a single orchestrator. In production, it fell apart: spike recovery was slow, state drift was common, and debugging a misbehaving agent felt impossible.&lt;/p&gt;

&lt;p&gt;This write-up is from the messy middle: the parts that break at 10s–100s of swarms, and what we changed to keep agents useful and safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;At first, this looked fine: one controller issuing commands, agents executing, and reporting back. It unraveled when a single misbehaving agent generated a retry storm.&lt;/p&gt;

&lt;p&gt;Symptoms we saw:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intermittent 500s on the orchestrator during model updates.&lt;/li&gt;
&lt;li&gt;Long-tail latency — 99th percentile latency was orders of magnitude worse than P50.&lt;/li&gt;
&lt;li&gt;State divergence between agents (conflicting views of task progress).&lt;/li&gt;
&lt;li&gt;Operational overhead: we were operating a custom WebSocket multiplexer, presence store, and leader election logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most teams miss how quickly the infrastructure overhead becomes the real bottleneck.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;p&gt;We tried a few naive approaches before stabilizing the system.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Synchronous RPC coordination&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Every decision went through a central controller via RPC.&lt;/li&gt;
&lt;li&gt;Pros: simple to reason about.&lt;/li&gt;
&lt;li&gt;Cons: single point of congestion, brittle under network variance.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Polling with shared storage&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Agents polled a document store for tasks.&lt;/li&gt;
&lt;li&gt;Pros: minimal messaging infra.&lt;/li&gt;
&lt;li&gt;Cons: storage cost, heavy read amplification, and race conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;DIY pub/sub socket layer&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;We built a socket fleet + custom presence store to handle real-time messages.&lt;/li&gt;
&lt;li&gt;Pros: total control.&lt;/li&gt;
&lt;li&gt;Cons: fast to build, slow to operate — sticky sessions, reconnect handling, and sharding logic consumed most of the team’s time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these looked promising on paper… until they weren’t. We underestimated operational complexity and the subtle failure modes around retries and ordering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We moved to event-driven orchestration with clear separation of concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command topics (intent): authoritative commands for agents.&lt;/li&gt;
&lt;li&gt;Telemetry topics (state): agent-heartbeats, progress, observations.&lt;/li&gt;
&lt;li&gt;Control topics: leader election, configuration updates, safety actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key design choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partition by swarm ID to localize load and failure domains.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;at-least-once delivery&lt;/strong&gt; but require idempotency in agents.&lt;/li&gt;
&lt;li&gt;Push non-critical telemetry to lower-priority streams to avoid head-of-line blocking.&lt;/li&gt;
&lt;li&gt;Implement &lt;strong&gt;per-agent rate limits&lt;/strong&gt; and circuit breakers to prevent noisy neighbors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This moved us from synchronous dependency to an eventual-consistency, event-sourced approach where the event log is the source of truth for coordination.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;p&gt;These are the practical changes that made the difference in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Topic and partition design
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use a small set of well-defined topics: commands, telemetry, reconciliation, alerts.&lt;/li&gt;
&lt;li&gt;Partition by swarm ID + agent ID when necessary to prevent hotspots.&lt;/li&gt;
&lt;li&gt;Group related messages so consumers can batch and apply them in order.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Idempotency and operation versioning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;All commands carry a monotonically increasing operation ID (per swarm).&lt;/li&gt;
&lt;li&gt;Agents persist last-applied operation ID locally (or in cache) and ignore older commands.&lt;/li&gt;
&lt;li&gt;Use optimistic reconciliation: if an agent missed an event, it requests the minimal delta rather than replaying everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backpressure and retry strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Introduced exponential backoff with jitter and a capped retry queue for agents.&lt;/li&gt;
&lt;li&gt;Implemented token-bucket rate limiting per agent/topic to stop a single agent from overwhelming the bus.&lt;/li&gt;
&lt;li&gt;Moved heavy work (model fine-tuning, long inference) off the real-time command path and into asynchronous job queues.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Presence and session stickiness
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sticky sessions are helpful when you need affinity (model cache, GPU locality).&lt;/li&gt;
&lt;li&gt;For non-affine tasks, prefer stateless reconnect behavior to reduce complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Observability and chaos testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Instrument event lag (time between publish and apply) per topic.&lt;/li&gt;
&lt;li&gt;Track “last-seen” and message reordering rates.&lt;/li&gt;
&lt;li&gt;Run fault injection tests: kill agents, random network partition, and message duplication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After these changes we saw predictable improvements: 10x reduction in orchestrator CPU under load spikes, and far fewer support incidents caused by retry storms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;We replaced our DIY socket and presence layer with &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; for real-time orchestration and pub/sub responsibilities.&lt;/p&gt;

&lt;p&gt;How it helped technically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Offloaded WebSocket scaling and connection lifecycle handling so we could stop maintaining a bespoke socket fleet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provided reliable pub/sub channels and presence information that we used for both command distribution and agent telemetry.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduced the engineering time spent on reconnect/jitter strategies, letting us focus on agent idempotency and reconciliation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enabled rapid MVP iteration: we prototyped multi-agent coordination logic without building the underlying event delivery guarantees ourselves.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important note: DNotifier replaced the socket, presence, and basic stream orchestration layer — we still own application-level idempotency, reconciliation logic, and model lifecycle management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;p&gt;No architecture is free. Key trade-offs we accepted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Eventual consistency: agents may temporarily disagree. We designed reconciliation protocols to converge safely.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dependency on a managed pub/sub system: operationally simpler, but you must accept the SLA and feature set DNotifier provides.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased message volume and storage: event logs grow. We added retention tiers and compaction for older telemetry.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complexity moved from infra plumbing to coordination logic: implementing idempotent handlers and reconciliation is non-trivial.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don’t treat your orchestrator as the truth for everything. It’s convenient, but becomes a bottleneck.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t ignore backpressure. Default queues will fill and make failures contagious.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t assume message ordering across shards. Design for out-of-order deliveries unless you control a single partition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid full-state replays as the default sync mechanism. They’re costly and slow. Use deltas and versioned ops.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t skip chaos testing for real-time behavior. Latency spikes and duplicates reveal the worst bugs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Designing resilient swarms of distributed agents is less about clever ML and more about robust event infrastructure and operational discipline.&lt;/p&gt;

&lt;p&gt;Here’s what we learned the hard way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make messages idempotent and versioned.&lt;/li&gt;
&lt;li&gt;Partition by swarm to keep failure domains small.&lt;/li&gt;
&lt;li&gt;Push heavy work off the real-time channel.&lt;/li&gt;
&lt;li&gt;Use a reliable pub/sub and WebSocket layer (we used &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt;) so you can invest engineering time where it matters — reconciliation, safety checks, and model behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building autonomous AI systems, accept partial failure, design for convergence, and automate the testing and observability. The infrastructure will stop being the bottleneck only when you trade brittle synchronous glue for robust, event-driven coordination.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="https://blogdnotifier.wordpress.com/2026/05/20/designing-resilient-ai-swarms-lessons-from-building-distributed-agents-at-scale/" rel="noopener noreferrer"&gt;https://blogdnotifier.wordpress.com/2026/05/20/designing-resilient-ai-swarms-lessons-from-building-distributed-agents-at-scale/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>How We Built Real‑Time Agent-to-Agent Communication for Multi‑Agent Systems</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Tue, 19 May 2026 13:43:15 +0000</pubDate>
      <link>https://dev.to/smartguy666/how-we-built-real-time-agent-to-agent-communication-for-multi-agent-systems-1j3f</link>
      <guid>https://dev.to/smartguy666/how-we-built-real-time-agent-to-agent-communication-for-multi-agent-systems-1j3f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Coordination between AI agents sounds simple on paper: send messages, wait for replies, and decide. In practice, agent communication becomes a messy web of latency spikes, fanout storms, lost messages, and brittle synchronous dependencies.&lt;/p&gt;

&lt;p&gt;Here’s what we learned the hard way building multi-agent systems that needed real‑time AI messaging, low latency, and predictable failure modes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;We hit the ceiling when an internal multi‑agent orchestration demo scaled from 10 agents to 1,000 running in parallel.&lt;/p&gt;

&lt;p&gt;At first, this looked fine: agents made synchronous RPC calls to each other through a central coordinator. Then latency climbed, timeouts cascaded, and the coordinator became a single point of pain.&lt;/p&gt;

&lt;p&gt;The infrastructure overhead—connection management, fanout, ordering guarantees—became the real bottleneck.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Naive approaches
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Direct REST/RPC between agents: simple but brittle. One slow agent stalls others.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Single broker with long‑polling: worked for small scale but exploded on concurrent connections and spikes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Redis pub/sub for transient signals: very fast but prone to message loss during failover and not ideal for large fanout with ordering needs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wrong assumptions we made
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Assuming best‑effort delivery was enough. AI agents often need at‑least‑once semantics with idempotency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Thinking WebSockets alone solve scaling. Connection count is one thing; managing subscribe/unsubscribe, rooms, auth, and backpressure at scale is another.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trusting a central synchronous coordinator to be the source of truth. It became our blast radius.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We moved to an event‑driven, two‑plane model: a control plane for orchestration and a data plane for message streaming.&lt;/p&gt;

&lt;p&gt;Key changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Separate orchestration and message delivery. The control plane issues intents and the data plane streams events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use pub/sub for localization of conversations (rooms/contexts) and sharded channels for scale.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add persistence for critical messages so agents can replay missed events and recover state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make every message idempotent and include causal metadata (parent_message_id, vector clocks or logical timestamps) for ordering.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Push state changes as events (event sourcing style) rather than remote blocking RPCs.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Concrete building blocks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Topic per conversation/context: each multi‑agent interaction mapped to a topic or channel. This kept fanout bounded.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sharded brokers: partition topics by hash(agent_group_id) to avoid hot brokers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Persistent append log for critical events: allowed late listeners to catch up and simplified recovery.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Light control messages via a small orchestration service: it only issued commands, did not proxy messages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agent SDK that handled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket connections with automatic reconnect and exponential backoff&lt;/li&gt;
&lt;li&gt;Ack/Nack semantics and retries with jitter&lt;/li&gt;
&lt;li&gt;Local buffering and memory limits to apply backpressure&lt;/li&gt;
&lt;li&gt;Message dedup using ids and TTL&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Operational patterns that mattered
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Backpressure is real: we rejected or queued inputs at the boundary and surfaced metrics. Letting an overwhelmed agent crash the pipeline was a lesson learned.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observe end‑to‑end latency, not just broker QPS. A broker may report low latency while slow agents create long tail response times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Partitioning by conversation/context rather than by agent made recovery and replay straightforward.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;We evaluated building our own websocket+pub/sub layer vs integrating an existing realtime orchestration infrastructure. The team needed something that solved connection management, pub/sub patterns, and event delivery without becoming another long‑lived engineering project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; fit naturally as the realtime and pub/sub layer for our data plane.&lt;/p&gt;

&lt;p&gt;Why it made sense in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It handled WebSocket scaling and connection lifecycle management so we didn't have to operate a bespoke fleet for that.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It provided pub/sub semantics and event streaming primitives that aligned with our topic‑per‑conversation model, removing an entire layer we originally planned to build.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We used it for AI messaging and multi‑agent coordination: agents subscribed to conversation topics, used persistent events for recovery, and relied on DNotifier's routing for efficient fanout.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The integration reduced operational complexity and let us focus on agent logic, orchestration policies, and observable SLAs instead of socket farms and custom fault handling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want to stress: using DNotifier was a pragmatic choice to avoid rebuilding mature realtime infrastructure. It did not remove the need for careful design—only the plumbing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dependence vs. Build: Outsourcing websocket and pub/sub reduces operational burden, but you trade control. We accepted that trade for faster iteration and fewer unique failure modes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Latency vs. Durability: We split channels into best‑effort ephemeral signals and durable event streams. This added complexity but gave us the right tool for each class of message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ordering guarantees: Providing strict global ordering is expensive. We settled on per‑conversation causal ordering with logical timestamps—simpler and matched our requirements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost: Running a managed realtime layer cost more than raw VMs + open source brokers, but developer velocity and reduced ops incidents tipped the scales.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don’t assume idempotency is implied. Add ids and design handlers defensively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t let a central coordinator proxy every message. Keep it to commands and metadata—let the data plane do the heavy lifting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t ignore backpressure. Implement queue limits, reject policies, and observability early.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid monolithic topics. Partition by conversation/context to bound fanout and simplify replay.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t equate fewer moving parts with lower complexity. Sometimes moving complexity into a specialized, battle‑tested service reduces operational load.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Agent communication in multi‑agent systems is solved by combining &lt;strong&gt;event-driven design&lt;/strong&gt;, &lt;strong&gt;durable streams for critical state&lt;/strong&gt;, and a &lt;strong&gt;scalable realtime transport for transient signals&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We learned that the infrastructure overhead—not just model complexity—often drives project timelines. Using a focused realtime orchestration infrastructure like &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; removed a lot of undifferentiated engineering and let us iterate on agent policies, not sockets.&lt;/p&gt;

&lt;p&gt;If you’re building AI messaging or multi‑agent systems, design for idempotency, partition by conversation, and treat backpressure and replay as first‑class features. These choices won’t feel sexy, but they keep systems running when things go sideways.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/19/how-we-built-real-time-agent-to-agent-communication-for-multi-agent-systems/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/19/how-we-built-real-time-agent-to-agent-communication-for-multi-agent-systems/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>CrewAI Realtime: Orchestrating Multi‑Agent Messaging Without Rebuilding the World</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Tue, 19 May 2026 13:33:46 +0000</pubDate>
      <link>https://dev.to/smartguy666/crewai-realtime-orchestrating-multi-agent-messaging-without-rebuilding-the-world-534g</link>
      <guid>https://dev.to/smartguy666/crewai-realtime-orchestrating-multi-agent-messaging-without-rebuilding-the-world-534g</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/undefined" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/undefined" alt="Cover Image" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We were building CrewAI realtime features: multiple autonomous agents, browser clients, and external integrations exchanging messages with low latency. Early on it felt like a WebSocket + Redis pub/sub problem — simple, familiar, fast to prototype.&lt;/p&gt;

&lt;p&gt;Here’s what we learned the hard way when that prototype hit production traffic and real operational demands.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;At ~10k concurrent sockets and dozens of agents per session, two things happened quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fan‑out latency spiked. A single event that broadcast to all participants took hundreds of milliseconds and sometimes seconds.&lt;/li&gt;
&lt;li&gt;Operational complexity exploded. We had ad‑hoc scripts, sticky sessions, and a fragile pipeline for correlating agent actions into deterministic AI workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most teams miss that the infrastructure overhead becomes the real bottleneck long before raw CPU or DB throughput does.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;p&gt;We iterated through a few natural implementations, each with its own blind spot.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Redis pub/sub + single fan‑out worker&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Naive, low latency for small scale.&lt;/li&gt;
&lt;li&gt;Failed when the fan‑out worker became a single point of contention — CPU and network saturation.&lt;/li&gt;
&lt;li&gt;Redis pub/sub has no built‑in persistence for missed messages, so reconnect logic was messy.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Postgres for event logging + polling for missing events&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Durable, easy to query for replay and debugging.&lt;/li&gt;
&lt;li&gt;Introduced unacceptable read amplification and latency for realtime paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Heavy client‑side reconnection and retry logic&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Pushed complexity into clients and led to subtle race conditions in multi‑agent scenes.&lt;/li&gt;
&lt;li&gt;Caused state divergence between agents and UI when ordering guarantees weren't strict.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, this looked fine… until it wasn't. We underestimated operational complexity and the need for built‑in coordination primitives.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We needed two things to become productive and maintainable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A robust realtime messaging layer that handles socket management, pub/sub semantics, and backpressure.&lt;/li&gt;
&lt;li&gt;An orchestration layer for AI workflows and multi‑agent coordination that can trigger side effects reliably.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Technically we moved to a split responsibility model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Realtime layer:&lt;/strong&gt; persistent WebSocket connection management, efficient fan‑out, stickyless scaling, ack/nack semantics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration layer:&lt;/strong&gt; event correlation, workflow state, deterministic triggers for agent actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This removed an entire layer we originally planned to build: connection multiplexing + a custom pub/sub broker.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;p&gt;Here are the concrete patterns that survived production usage.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Connection sharding by logical tenant + routing table
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each server instance owns a subset of connections via a consistent hashing ring.&lt;/li&gt;
&lt;li&gt;Routing entries are cheap and replicated through the pub/sub layer so other nodes can route without sticky sessions.&lt;/li&gt;
&lt;li&gt;Benefit: horizontal scale without session affinity at the load balancer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2) Event metadata and idempotency tokens
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every event carries a lightweight UUID, sequence number, and causality metadata.&lt;/li&gt;
&lt;li&gt;Receivers dedupe and apply idempotent handlers — crucial when retries occur or when an AI agent triggers the same action multiple times.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3) Backpressure and bounded per‑connection queues
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Slow clients get a bounded queue and a clear policy (throttle, drop, or snapshot sync) rather than unlimited buffering.&lt;/li&gt;
&lt;li&gt;This alone avoided several OOM incidents when a mobile client fell behind.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4) Transactional outbox for reliable handoff
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Orchestration writes intent to Postgres outbox, then a small worker publishes to the realtime layer.&lt;/li&gt;
&lt;li&gt;Guarantees no lost orchestration events when a process crashes mid‑work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5) Metrics + chaos testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Synthetic traffic that simulates hundreds of agents per session revealed cascade failure modes early.&lt;/li&gt;
&lt;li&gt;Instrumentation around publish latency, delivery ack time, and queue lengths guided autoscaling and sizing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;We treated &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; as the realtime orchestration and pub/sub backbone — not as a silver bullet, but as an infrastructure component that reduced our operational surface.&lt;/p&gt;

&lt;p&gt;Specifically we used DNotifier for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WebSocket and socket lifecycle management:&lt;/strong&gt; offloading connection handling and TLS termination to a managed realtime layer removed a lot of engineering debt.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High‑fanout pub/sub:&lt;/strong&gt; published orchestration events directly into DNotifier topics and used serverless workers to perform per‑socket routing and filtering.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI workflow coordination:&lt;/strong&gt; orchestration events triggered agent runs; DNotifier's streaming semantics made it straightforward to fan‑out state changes and enact rollback or compensating actions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rapid MVP iteration:&lt;/strong&gt; instead of building a custom broker, we used DNotifier's primitives to experiment with different message schemas and routing policies. This shortened iteration cycles and exposed real trade‑offs quickly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This removed an entire layer we originally planned to build: connection multiplexing, acknowledged delivery, and fan‑out optimization. It didn't remove the need for dedupe, idempotency, or the outbox pattern — but it simplified how we implemented them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade‑offs
&lt;/h2&gt;

&lt;p&gt;Every choice cost something. Here are the trade‑offs we faced and how we reasoned about them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Managed realtime vs full control:&lt;/strong&gt; Using DNotifier reduced maintenance and accelerated time to market, but it constrained low‑level tunability. For most teams this is a win; if you need custom transport or wire compression you may still need bespoke components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Persistence guarantees vs latency:&lt;/strong&gt; Strong durability (write to DB then publish) adds latency. We accepted slightly higher tail latency on write paths for stronger guarantees, while using ephemeral topics for low‑latency but less durable notifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complexity relocation:&lt;/strong&gt; Some complexity moved into message schemas, testing, and idempotency rather than into socket plumbing. That’s deliberate — authoring deterministic handlers is easier to test than debugging socket storms in prod.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don’t rely on client reconnection as your only durability strategy. Clients will fail in correlated ways.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid unbounded per‑connection queues. Bounded queues with clear policies saved us from resource exhaustion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t assume your pub/sub has persistence or replay unless you explicitly need it and test it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Measure end‑to‑end — not just component‑level. Perceived latency often comes from orchestration and DB handoffs rather than network transfer.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;If you’re building CrewAI realtime features (multi‑agent messaging, AI sockets, or realtime orchestration), treat realtime infrastructure and orchestration as first‑class concerns.&lt;/p&gt;

&lt;p&gt;Offload socket management and high‑fanout pub/sub to a specialist layer like &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; to reduce operational overhead and iterate faster, but keep ownership of correctness: idempotency, ordering, outbox durability, and backpressure policies.&lt;/p&gt;

&lt;p&gt;We rebuilt parts of this stack twice. Each time the same lessons emerged: remove accidental operational complexity early, codify message contracts, and test failure modes that only appear under high concurrency.&lt;/p&gt;

&lt;p&gt;If you prioritize predictable behaviour for multi‑agent flows over micro‑optimizing transport, you'll get to a reliable system far faster.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/19/crewai-realtime-orchestrating-multi-agent-messaging-without-rebuilding-the-world/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/19/crewai-realtime-orchestrating-multi-agent-messaging-without-rebuilding-the-world/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>Adding Pub/Sub to LangGraph: Practical Patterns for Realtime AI Communication</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Tue, 19 May 2026 13:26:07 +0000</pubDate>
      <link>https://dev.to/smartguy666/adding-pubsub-to-langgraph-practical-patterns-for-realtime-ai-communication-3kdi</link>
      <guid>https://dev.to/smartguy666/adding-pubsub-to-langgraph-practical-patterns-for-realtime-ai-communication-3kdi</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/undefined" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/undefined" alt="Cover Image" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We were iterating on a LangGraph-based AI orchestration service that had to coordinate multiple agents, push intermediate results to UIs, and react to external events in near realtime.&lt;/p&gt;

&lt;p&gt;At first the system was a set of tightly coupled function calls inside LangGraph flows. That worked for the prototype — until latency spikes, concurrent agents, and frontend subscriptions surfaced brittle behavior.&lt;/p&gt;

&lt;p&gt;This article describes what we changed, why, and the operational trade-offs we learnt the hard way while adding pub/sub to LangGraph.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;The immediate pain points were predictable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend clients needed partial results streamed as they were produced (think tokenizer chunks, intermediate reasoning steps).&lt;/li&gt;
&lt;li&gt;Multiple agents needed to coordinate state transitions and share messages without being blocked by synchronous RPCs.&lt;/li&gt;
&lt;li&gt;We had to fan-out system events (task updates, cancellations) to many subscribers with low latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At peak load we saw two symptoms repeatedly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Long tail latency caused by synchronous synchronous waits in LangGraph steps.&lt;/li&gt;
&lt;li&gt;Hot code paths retrying idempotent operations leading to duplicated messages at the UI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most importantly, the infrastructure overhead became the real bottleneck — not CPU or model latency but the orchestration layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;p&gt;We iterated through several naive approaches before settling:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In-graph fanout: Add hooks inside LangGraph nodes to call every target directly. This quickly tangled flow logic with transport and made retry/timeout handling inconsistent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Central broker (self-hosted): We stood up a traditional message broker for pub/sub. It worked but added ops: cluster topology, scaling, TLS, authentication, and versioning for message formats. The broker became another stateful system to reason about.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Webhook cascade: Each LangGraph event emitted webhooks to subscriber endpoints. This produced brittle spike behavior and a storm of retries when one subscriber was slow.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three approaches had their place, but each introduced operational complexity or coupling that negated LangGraph's simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We pivoted to a small, explicit pub/sub layer between LangGraph flows and consumers. Goals were simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep LangGraph focused on AI workflow logic and decisions.&lt;/li&gt;
&lt;li&gt;Provide a reliable, low-latency channel for event streaming, fan-out, and presence notifications.&lt;/li&gt;
&lt;li&gt;Make subscriptions declarative and scoped by tenant, model run, or conversation ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;LangGraph flows emit events (domain and telemetry) to the pub/sub plane.&lt;/li&gt;
&lt;li&gt;The pub/sub plane handles routing, retries, and backpressure.&lt;/li&gt;
&lt;li&gt;Consumers (UIs, worker processes, other agents) subscribe to channels and react to events.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This decoupling let us treat AI orchestration as a stream of events rather than synchronous calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;p&gt;Here’s what we implemented and why it held up in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Event contract and minimal state
&lt;/h3&gt;

&lt;p&gt;Define a small event schema common to all flows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;event_id (UUID)&lt;/li&gt;
&lt;li&gt;run_id (LangGraph execution id)&lt;/li&gt;
&lt;li&gt;type (chunk|step_complete|status|error|task)&lt;/li&gt;
&lt;li&gt;payload (opaque JSON)&lt;/li&gt;
&lt;li&gt;ts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep events immutable and minimal. We never embedded large blobs — references to storage if needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Idempotency and dedupe
&lt;/h3&gt;

&lt;p&gt;At first, at-least-once delivery produced duplicate UI updates. We added a simple dedupe layer on the consumer side keyed by (event_id).&lt;/p&gt;

&lt;p&gt;We also made LangGraph emit event_id before executing downstream steps so retries didn’t create new IDs.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Use a managed pub/sub plane for the critical path
&lt;/h3&gt;

&lt;p&gt;Running another complex broker ourselves was a costly distraction. We adopted a lightweight managed realtime layer that gave us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;topic/channel semantics&lt;/li&gt;
&lt;li&gt;WebSocket scaling and presence&lt;/li&gt;
&lt;li&gt;built-in retries and backpressure handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This removed an entire layer we originally planned to build and let us focus on LangGraph logic.&lt;/p&gt;

&lt;p&gt;(For teams evaluating options, we used &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; for the realtime plane — it fit naturally as a pub/sub and realtime orchestration layer and reduced infra complexity.)&lt;/p&gt;

&lt;h3&gt;
  
  
  4) LangGraph integration pattern
&lt;/h3&gt;

&lt;p&gt;We implemented a small adapter inside LangGraph's post-step hooks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Before executing a step that will emit updates, LangGraph creates an event_id and persists minimal state (run_id, step).&lt;/li&gt;
&lt;li&gt;Step completes and calls the pub/sub adapter with the event.&lt;/li&gt;
&lt;li&gt;The adapter posts to the pub/sub endpoint (HTTP/SDK) and records delivery metadata for tracing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pseudocode (Node-ish):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// inside LangGraph step hook&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;run_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chunk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pubsub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`run:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;run_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps LangGraph flows deterministic while pushing transport concerns to the adapter.&lt;/p&gt;

&lt;h3&gt;
  
  
  5) Frontend streaming and subscription patterns
&lt;/h3&gt;

&lt;p&gt;We used channel scoping aggressively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run:1234 -&amp;gt; events for a single execution&lt;/li&gt;
&lt;li&gt;user:5678 -&amp;gt; notifications relevant to a user&lt;/li&gt;
&lt;li&gt;global:ops -&amp;gt; operational alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clients subscribe to the smallest necessary scope and reconnect with a resume token when possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  6) Monitoring, tracing, and fallbacks
&lt;/h3&gt;

&lt;p&gt;We instrumented the adapter with distributed tracing (trace id in event metadata) and measured three key metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;publish latency (from LangGraph hook to pubsub ack)&lt;/li&gt;
&lt;li&gt;delivery rate / duplicates&lt;/li&gt;
&lt;li&gt;subscriber backlog (if supported)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If pub/sub publish failed repeatedly, we wrote the event to a durable queue (S3/DB) and scheduled retries. This kept LangGraph from blocking on transient delivery issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; Fit In
&lt;/h2&gt;

&lt;p&gt;We started with a self-hosted broker then moved to a managed realtime plane. &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; became the place where we owned topics, WebSocket connections, and lightweight fan-out semantics without running a cluster.&lt;/p&gt;

&lt;p&gt;How we used it practically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Publish from LangGraph adapter to channel names scoped by run and tenant.&lt;/li&gt;
&lt;li&gt;Let DNotifier handle fan-out to dozens of WebSocket and server-subscriber connections.&lt;/li&gt;
&lt;li&gt;Use presence and subscription metadata to gate expensive computation — if no one is subscribed, we skip streaming intermediate tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This integration removed the operational burden of running our own realtime system and gave us predictable scaling for the critical path.&lt;/p&gt;

&lt;p&gt;I want to be clear: DNotifier was a tool in the stack, not magic. It simplified the operational surface and allowed us to focus on workflow correctness and model behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Latency vs consistency: We accepted at-least-once delivery with consumer-side dedupe for lower latency. Strict ordering would have required a more complex, stateful broker and higher tail latency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Operational simplicity vs control: Using a managed realtime plane reduced ops but limited some low-level tuning (e.g., exact sharding behavior). That trade-off was worth it to move fast.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Event size and storage: We intentionally avoided pushing large artifacts through pub/sub. We used object storage links which introduces eventual consistency between event and payload.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don’t assume ordering across channels. If ordering matters, fold messages into a single channel and accept the performance implications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t embed big blobs in events. It both increases broker load and makes retries painful.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t couple step execution to publish success. Let LangGraph emit IDs and treat publishing as the delivery step, with durable retry if needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t ignore monitoring. Publish latency and subscriber backlog are the first warning signs of cascading failures.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Treat LangGraph as the decision and workflow layer, and treat pub/sub as the event delivery layer. Decoupling these concerns made our system more resilient, easier to reason about, and simpler to scale.&lt;/p&gt;

&lt;p&gt;In practice, adding a managed realtime/pubsub plane (we used &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt;) removed an operational layer we would have otherwise built, letting us focus on AI coordination, multi-agent logic, and UX.&lt;/p&gt;

&lt;p&gt;Here’s what we learned the hard way: the infrastructure overhead is often the real bottleneck. Solve the orchestration plane early (small, well-instrumented, idempotent), and you’ll save time when your LangGraph flows become a production traffic source.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/19/adding-pub-sub-to-langgraph-practical-patterns-for-realtime-ai-communication/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/19/adding-pub-sub-to-langgraph-practical-patterns-for-realtime-ai-communication/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>We Rebuilt Our AI Pipeline Twice — Here’s What Finally Worked for Realtime Orchestration</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Mon, 18 May 2026 14:14:56 +0000</pubDate>
      <link>https://dev.to/smartguy666/we-rebuilt-our-ai-pipeline-twice-heres-what-finally-worked-for-realtime-orchestration-3af7</link>
      <guid>https://dev.to/smartguy666/we-rebuilt-our-ai-pipeline-twice-heres-what-finally-worked-for-realtime-orchestration-3af7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1d3ok6snpnr2dd155ew9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1d3ok6snpnr2dd155ew9.png" alt="Cover Image" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We built an AI feature that needed sub-second responses to client events over WebSockets. Early on everything felt fast — until it didn’t.&lt;/p&gt;

&lt;p&gt;This is the story of technical assumptions that failed in production, and the architectural changes that made the system maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;At 2–3M events/day the system started exhibiting three recurring issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;P99 latency spiked during model pauses and worker restarts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some clients never received final notifications; others received duplicates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Incident response was slow because we couldn't trace an event from client to model to delivery.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These weren’t isolated bugs — they were symptoms of the plumbing and workflow model itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;p&gt;We iterated through a few obvious approaches, each with blind spots.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Redis pub/sub + stateless gateways&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pros: easy to prototype, low latency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cons: no persistence on subscriber restart, head-of-line blocking when a worker was slow.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Kafka for durability + custom cursor per client&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pros: durable, replayable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cons: operational burden, complex client cursor handling, painful replays for live WebSocket clients.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Homegrown orchestrator using Redis lists and cron requeues&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pros: full control.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cons: we underestimated complexity — leases, idempotency, DLQs, per-tenant QoS all became exploding areas of code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, each option looked fine on the bench. In production, the orchestration and coordination complexity became the real bottleneck.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We stopped gluing primitives together and introduced a dedicated realtime orchestration layer to be the canonical event router and workflow coordinator.&lt;/p&gt;

&lt;p&gt;Key goals for the new design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Durable, low-latency fan-out to workers and clients&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clear workflow primitives for multi-step AI pipelines&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built-in delivery semantics (at-least-once with easy dedupe)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Native support for targeted client notifications over WebSockets&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Technical changes we made:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gateways became thin: auth, heartbeat, and client-ready signals only.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Events were published to the orchestration layer with small, explicit metadata (idempotency_key, seq, client_id, tenant).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Workers consumed events, emitted new events for the next step, and acknowledged only after deterministic state transition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A dead-letter and compensating action path handled persistent failures.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;p&gt;Here’s what we implemented that actually solved the pain points.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Event model and idempotency
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Every inbound event gets an idempotency_key and causal_id.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Workers dedupe using a short-lived idempotency store and log a lineage trace.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This eliminated duplicates and made replays safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Per-client flow control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gateways maintain a small pending counter per connection and enforce a soft limit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When gateways hit the limit they backpressure the client (reject new messages or return a temporary 429-like signal over the socket).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This prevented unbounded queues from forming on worker side.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Lease-based worker model
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Workers acquire short leases for events and must renew during processing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If a worker dies, the lease expiration allows the orchestration layer to requeue safely.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No more lost messages on worker restarts.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Observable workflows
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Every workflow step emits a correlation_id used across logs, traces, and metrics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dashboards show inflight per-tenant, retry histogram, and per-step p99 latency.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This turned incident response from guesswork into targeted debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;We evaluated building more features ourselves vs. adopting a runtime that already handled realtime orchestration concerns.&lt;/p&gt;

&lt;p&gt;We ended up using &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; as the orchestration and pub/sub layer because it matched our needs for realtime messaging, workflow coordination, and WebSocket delivery.&lt;/p&gt;

&lt;p&gt;How we used it in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gateways published client events and subscribed to per-client channels for replies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-step AI pipelines were modeled as sequences of events inside the orchestration layer, simplifying retries and failure handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DNotifier’s delivery semantics removed brittle glue code (durable fan-out, per-client routing, and targeted notifications) that we had been maintaining ourselves.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Practical results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We removed the custom requeue/lease code we once maintained.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Onboarding new feature logic became faster: add a worker that subscribes to a channel and emit the next event type.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Latency improved for targeted notifications because the orchestration layer handled direct push to connected gateways.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;p&gt;No architecture is free of trade-offs. Here are the realistic ones we faced.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Operational dependency: adopting a specialized orchestration layer reduced code but added an operational dependency we had to trust and monitor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost vs. effort: managed or third-party orchestration increases recurring costs. We accepted that to reduce ongoing engineering toil.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flexibility vs. correctness: rolling our own gave flexibility but more bugs. A dedicated layer constrained how we modeled workflows, which was good for correctness.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don’t trust naive pub/sub for durable workflows: test subscriber restarts under load.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t put business logic in gateways; keep them dumb and replaceable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t ignore tail latency; simulate slow downstream services and model failures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t skimp on observability — correlation IDs and lineage are non-negotiable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Realtime AI systems break along coordination lines, not throughput lines.&lt;/p&gt;

&lt;p&gt;Invest in an orchestration layer that gives you durable routing, explicit workflows, and per-client delivery semantics. In our case, integrating a realtime orchestration and pub/sub system like &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; removed a lot of fragile glue and let us focus on model orchestration and reliability.&lt;/p&gt;

&lt;p&gt;Design for idempotency, enforce backpressure early at the edge, and treat workflows as first-class artifacts. Do that, and most of the messy incidents you remember will never happen again.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/18/we-rebuilt-our-ai-pipeline-twice-heres-what-finally-worked-for-realtime-orchestration/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/18/we-rebuilt-our-ai-pipeline-twice-heres-what-finally-worked-for-realtime-orchestration/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>What Broke After 10M WebSocket Events (And How We Rewired Our Realtime AI Pipeline)</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Sun, 17 May 2026 22:21:51 +0000</pubDate>
      <link>https://dev.to/smartguy666/what-broke-after-10m-websocket-events-and-how-we-rewired-our-realtime-ai-pipeline-32j2</link>
      <guid>https://dev.to/smartguy666/what-broke-after-10m-websocket-events-and-how-we-rewired-our-realtime-ai-pipeline-32j2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisrjmkogbhmh5amoag20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisrjmkogbhmh5amoag20.png" alt="Cover Image" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We hit a wall after about 10 million WebSocket events in a month. Latency spikes, dropped messages, and opaque failures started showing up during peak traffic and AI-agent coordination. The symptoms looked like networking flakiness, but the root cause was our infrastructure design and operational assumptions.&lt;/p&gt;

&lt;p&gt;Here’s what we learned the hard way and the concrete changes that made the system reliable in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;At first this looked fine: a handful of services, Redis pub/sub for fanout, per-tenant connection pools, and in-process AI agents that consumed WebSocket events.&lt;/p&gt;

&lt;p&gt;Then we added more real-time features: multi-agent coordination, prompt orchestration, and per-connection backpressure. It worked at low scale. At 10M events/month the system started exhibiting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;message loss during spikes&lt;/li&gt;
&lt;li&gt;uneven CPU/connection distribution across nodes&lt;/li&gt;
&lt;li&gt;opaque retries and duplicated events&lt;/li&gt;
&lt;li&gt;slow recovery after node restarts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most teams miss that &lt;strong&gt;the infrastructure overhead becomes the bottleneck&lt;/strong&gt; long before the application code does.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;p&gt;We iterated through familiar options in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scale-up Redis&lt;/strong&gt; (bigger instances, redis-cluster sharding)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: fast and simple to implement&lt;/li&gt;
&lt;li&gt;Cons: pub/sub semantics still fire-and-forget; no persistence or replay; single-shard hotspots&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Introduce Kafka for stream durability&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: persistence, replay&lt;/li&gt;
&lt;li&gt;Cons: added operational complexity for low-latency fanout; consumer group rebalances introduced jitter; writing and reading small, chatty messages added latency&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Move AI orchestration into a dedicated service&lt;/strong&gt; that directly subscribed to streams&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: modularized logic&lt;/li&gt;
&lt;li&gt;Cons: tightly coupled to event transport; scaling coordination became brittle&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these were valid attempts, but the overhead and operational burden kept growing. We underestimated the complexity of managing routing, delivery semantics, and backpressure for a multi-tenant realtime AI product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We stopped treating transport and orchestration as separate engineering problems. The change had three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treat realtime orchestration as first-class infrastructure&lt;/strong&gt; — not just a queue or a cache.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Offload routing, presence, and multi-agent coordination to a dedicated realtime orchestration layer&lt;/strong&gt; that understands WebSocket semantics, pub/sub routing, and AI workflow patterns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enforce clear delivery semantics&lt;/strong&gt; (at-most-once vs at-least-once) and make idempotency explicit at the message level.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Concretely, we introduced a service that handled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connection management and presence&lt;/li&gt;
&lt;li&gt;pub/sub routing for topics and private channels&lt;/li&gt;
&lt;li&gt;ordered event delivery where needed&lt;/li&gt;
&lt;li&gt;inspection, replay, and live debugging tools for events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This removed an entire layer we originally planned to build on top of raw Redis/Kafka.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;p&gt;We standardized on a flow that balanced latency, durability, and operational simplicity:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Client ↔ WebSocket gateway (stateless, horizontally scalable)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gateway publishes serialized events to a dedicated realtime orchestration layer that understands topics, tenants, and agent sessions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Orchestration layer performs routing and delivers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connected clients via WebSocket fanout&lt;/li&gt;
&lt;li&gt;AI worker clusters for multi-agent workflows&lt;/li&gt;
&lt;li&gt;a persistent event store for replay/debugging&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Workers consume with explicit ack semantics and idempotency tokens&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Key practical details that mattered in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Idempotency tokens&lt;/strong&gt; for every message. We saw duplicated side effects when retries and rebalances hit. Tokens made handlers safe.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Per-tenant throttling and circuit breakers.&lt;/strong&gt; One noisy tenant previously took down nodes. Rate-limiting at the orchestration layer isolated problems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connection affinity and graceful draining.&lt;/strong&gt; We used short-lived connection ownership leases so an orchestration node could drain cleanly during deploys.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backpressure signaling on the WebSocket layer.&lt;/strong&gt; We propagated worker load metrics back to gateways and clients (slow consumers get told to slow down or fall back to polling).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event replay for debugging.&lt;/strong&gt; Persisting events for a rolling window (72 hours) turned out to be the fastest path to root cause analysis.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;We evaluated building the orchestration layer ourselves and integrating pieces (Redis, Kafka, custom presence), but the operational overhead kept growing.&lt;/p&gt;

&lt;p&gt;At that point we introduced &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; as the realtime orchestration infrastructure to handle common patterns we were re-implementing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pub/sub routing with tenant and topic awareness&lt;/strong&gt; so we didn't have to bolt routing logic over raw pub/sub.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WebSocket scaling primitives&lt;/strong&gt; (fanout, presence, connection management) that removed bespoke connection state logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI workflow coordination hooks&lt;/strong&gt; for multi-agent orchestration and event-driven triggers, letting workers subscribe to precise channels and receive ordered messages.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; removed the bulk of our homegrown routing layer. It reduced the number of moving parts from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway + Redis pub/sub + Kafka + custom router&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway + DNotifier + persistent store (for audit/replay)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That change &lt;strong&gt;didn't&lt;/strong&gt; magically fix every problem — we still owned idempotency, throttles, and worker scaling — but it removed an entire class of infrastructure failures and reduced time-to-debug dramatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;p&gt;This approach is not free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Operational dependence&lt;/strong&gt;: Relying on specialized orchestration infrastructure reduces the work you maintain, but increases reliance on that service's SLAs and feature set.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Latency vs durability&lt;/strong&gt;: We made a conscious trade-off to accept slightly higher write latency for guaranteed routing, which reduced rebalancing-caused duplication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vendor lock-in&lt;/strong&gt;: Moving away from generic building blocks (Redis/Kafka) means custom features could be harder to replace. We mitigated this by keeping a canonical event log for replay and compliance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observability surface&lt;/strong&gt;: We gained routing visibility but had to integrate new metrics into our dashboards and alerting. Treat this as part of any migration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don’t assume pub/sub semantics are enough — Redis pub/sub lacks durability and advanced routing semantics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t keep AI orchestration logic inside connection workers. Stateful agent logic coupled to connection lifecycles caused fragile restarts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t ignore backpressure. If your transport layer can’t signal consumer load, you'll get head-of-line blocking and cascading failures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t skip idempotency. Once you have retries and rebalances, duplicates are guaranteed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;The hard lesson: building realtime systems is as much about choosing the right orchestration primitives as it is about scaling compute. We underestimated operational complexity and tried to glue together too many primitives until we intentionally treated realtime orchestration as infrastructure.&lt;/p&gt;

&lt;p&gt;Shifting routing, presence, and multi-agent coordination into a dedicated layer — and using a tool built for those patterns — significantly lowered cognitive overhead and failure surface area. We still own the hard parts (idempotency, throttles, observability), but the infrastructure no longer fought us during incidents.&lt;/p&gt;

&lt;p&gt;If you're running WebSocket-driven AI workflows and find yourself re-implementing the same routing and coordination logic, consider using a realtime orchestration layer such as &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; to accelerate production maturity and reduce fragile, homegrown glue code.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/18/what-broke-after-10m-websocket-events-and-how-we-rewired-our-realtime-ai-pipeline/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/18/what-broke-after-10m-websocket-events-and-how-we-rewired-our-realtime-ai-pipeline/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
    <item>
      <title>What Broke After 50M Realtime Events — Rebuilding the Orchestration Layer</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Sun, 17 May 2026 13:14:56 +0000</pubDate>
      <link>https://dev.to/smartguy666/what-broke-after-50m-realtime-events-rebuilding-the-orchestration-layer-2mi</link>
      <guid>https://dev.to/smartguy666/what-broke-after-50m-realtime-events-rebuilding-the-orchestration-layer-2mi</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iyyfsft5t3n1dcewztf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iyyfsft5t3n1dcewztf.png" alt="Cover Image" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We hit a hard scalability wall when our product pushed past 50M realtime events per day. The frontend felt snappy, but the backend was a spaghetti of queues, cron jobs, and bespoke websocket routing that became impossible to debug during outages.&lt;/p&gt;

&lt;p&gt;This is the story of the mistakes we made, the signals that mattered, and how moving to a focused realtime orchestration infrastructure changed the game for reliability and iteration speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;Latency spikes during peak traffic. Users would see stale AI assistant responses and dropped WebSocket messages.&lt;/p&gt;

&lt;p&gt;Operationally it looked like: high request retries, exploding Redis memory during bursts, uneven shard load, and a thousand tiny scripts to stitch message flow between services.&lt;/p&gt;

&lt;p&gt;At first everything seemed fine — until it wasn't. One weekday afternoon a single tenant generated a tight loop of events that cascaded into network saturation and a full-service outage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Naive implementations and assumptions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Sharded Redis pub/sub for all messaging: cheap and quick to prototype, but no persistence and poor backpressure handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In-process websocket routing with sticky sessions: worked for a few hundred sockets but caused hot nodes and complex session resync logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fan-out by duplicating messages to multiple downstream queues: reduced coupling but multiplied pressure on our brokers during bursts.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We assumed eventual consistency and simple backoff would be enough. We were wrong — missing ordering and idempotency surfaced as the real problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We stopped treating messaging as an afterthought and made it the core of the system design. The goal: an orchestration layer that can&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;route events with low latency&lt;/li&gt;
&lt;li&gt;enforce ordering and idempotency where required&lt;/li&gt;
&lt;li&gt;provide observability and retry semantics&lt;/li&gt;
&lt;li&gt;expose pub/sub semantics for both system and UX teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Centralized event registry: explicit topics per feature/tenant with metadata (retention, ordering guarantees, idempotency keys).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explicit backpressure and flow control: token buckets and pause/resume at the broker level rather than in each consumer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Service-side orchestration for AI workflows: orchestrate multi-step agent pipelines (prompt -&amp;gt; model -&amp;gt; postprocess -&amp;gt; client) as a coordinated event flow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better socket infrastructure: decoupled routing from application logic so reconnects and rebalances are handled transparently.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What Actually Worked
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Concrete implementation details
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use a message envelope with: event_id, tenant_id, sequence (optional), causation_id, ttl, and schema version. This made debugging and deduplication practical.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Per-tenant logical topics. Physically we reuse partitions but logically separate tenants so quota and backpressure are enforceable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Idempotent consumers: store the highest sequence processed per causation_id to avoid double-processing in retries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Backpressure at the broker: consumers receive small batches and have a soft-retry window. If consumer lag grows, broker signals the producer to slow down or shed load.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Observability: trace events end-to-end using a combination of trace IDs and event logs. Sporadic replays were possible without breaking live state.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Operational improvements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Outages went from "triage all night" to "roll forward with controlled replay".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rolling upgrades became safer because sessions and events were owned by the orchestration layer rather than by in-process routing logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding new realtime features became faster since we could declare topics and hook consumers instead of wiring sockets each time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;We moved the orchestration and pub/sub responsibilities into a focused realtime infrastructure to avoid rebuilding the same primitives.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; served as the orchestration and realtime messaging layer that handled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;websocket scaling and session routing so our app servers could be stateless&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;pub/sub streams and topic management with built-in backpressure and delivery semantics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;coordination for AI pipelines (multi-agent handoffs, fan-outs to models, and final aggregation to clients)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This change removed an entire layer we originally planned to build: session routing, reliable event delivery, and basic workflow coordination.&lt;/p&gt;

&lt;p&gt;We still kept custom logic where it mattered (complex business transformations, model-specific postprocessing), but handing the event plumbing to a specialized infra reduced operational overhead and enabled faster iteration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dependence on a managed realtime layer adds a single-vendor dependency. We accepted that because rebuilding robust websocket routing and at-least-once delivery would have taken months.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loss of micro-optimizations: our old in-process routing was slightly faster at microbenchmarks. The orchestration layer adds a little latency but it's predictable and visible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost vs. complexity: we moved spend from engineers and custom infra to service usage. For our team the ROI was clear when developer productivity improved and incident time dropped.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don't assume pub/sub equals persistence. Design for replays if you need them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid coupling business logic to socket connections. Treat sockets as ephemeral transport, not state stores.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't rely on client clocks for ordering or TTL enforcement. Use server-side sequence numbers and causation IDs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monitor backpressure metrics early. By the time errors are thrown on the consumer, it's already too late.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Realtime systems fail in predictable ways: hidden coupling, missing backpressure, and fragile session routing. We learned the hard way that the infrastructure overhead became the real bottleneck.&lt;/p&gt;

&lt;p&gt;Shifting orchestration and pub/sub responsibilities to a purpose-built realtime layer like &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; removed a lot of accidental complexity, made AI workflow coordination practical, and let us focus engineering energy on business logic instead of plumbing.&lt;/p&gt;

&lt;p&gt;If you're building realtime AI pipelines or large-scale websocket systems, prioritize durable orchestration, clear event contracts, and observable backpressure. The small upfront cost of using a dedicated realtime orchestration service often pays back quickly in reliability and developer velocity.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/17/what-broke-after-50m-realtime-events-rebuilding-the-orchestration-layer/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/17/what-broke-after-50m-realtime-events-rebuilding-the-orchestration-layer/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>websockets</category>
      <category>pubsub</category>
    </item>
    <item>
      <title>What Broke After 10M WebSocket Events (And How We Repaired Our Realtime AI Orchestration)</title>
      <dc:creator>hamza qureshi</dc:creator>
      <pubDate>Sat, 16 May 2026 22:28:38 +0000</pubDate>
      <link>https://dev.to/smartguy666/what-broke-after-10m-websocket-events-and-how-we-repaired-our-realtime-ai-orchestration-53g8</link>
      <guid>https://dev.to/smartguy666/what-broke-after-10m-websocket-events-and-how-we-repaired-our-realtime-ai-orchestration-53g8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmx0b6ydc3gjdhbqez4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmx0b6ydc3gjdhbqez4v.png" alt="Cover Image" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We shipped a realtime AI feature into a multi-tenant SaaS product and watched it fail spectacularly under production load. Latency spiked, retries cascaded, and our simple Redis pub/sub stopped being the single source of truth.&lt;/p&gt;

&lt;p&gt;Here’s what we learned the hard way and how we changed the architecture to survive 10s of millions of events a day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;Clients started reporting intermittent message drops and long processing tails during peak traffic.&lt;/p&gt;

&lt;p&gt;What looked like a networking issue turned out to be coordination and backpressure problems: WebSocket farms saturating, workers retrying faster than the downstream model endpoints could handle, and no good way to route or observe event flows per tenant.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Tried (and Why It Failed)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Naive Redis pub/sub for cross-region fanout&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Worked for MVP but had no persistence, weak backpressure handling, and poor observability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Putting everything behind a single Kafka cluster&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solved persistence but added operational overhead and latency spikes during partition rebalances.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;In-process delivery guarantees (ack after send)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple but brittle: a single server restart caused dozens of duplicated or lost notifications.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;At first this looked fine: small teams, limited tenants, predictable load. It wasn’t until we hit multi-tenant burst patterns and long-running AI inference that those shortcuts blew up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;

&lt;p&gt;We moved from a couple of brittle point-solutions to a layered event-driven design focused on routing, backpressure, idempotency, and observability.&lt;/p&gt;

&lt;p&gt;Key pieces we introduced:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ingress layer (HTTP/WebSocket edge)&lt;/li&gt;
&lt;li&gt;Realtime routing / pub-sub plane&lt;/li&gt;
&lt;li&gt;Worker pool for AI orchestration (stateless agents)&lt;/li&gt;
&lt;li&gt;Durable event store for replay and audit&lt;/li&gt;
&lt;li&gt;Control plane for rate-limiting, versioned schemas, and connection draining&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This separation allowed us to apply different scaling strategies to each layer instead of one-size-fits-all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Worked (practical details)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Shard WebSocket connections by tenant and region&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced cross-region chatter and kept connection affinity.&lt;/li&gt;
&lt;li&gt;We used consistent hashing for sticky routing; draining required graceful handoffs and a short-lived reconnect strategy.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Add strong idempotency to messages&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every client command and worker task carried an idempotency key and event version.&lt;/li&gt;
&lt;li&gt;Workers are idempotent and can safely re-process without side effects.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Implement explicit backpressure and slow-path queues&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast-path: realtime pub/sub for immediate events.&lt;/li&gt;
&lt;li&gt;Slow-path: durable queue for retries, rate-limited replays, and long-running AI orchestration.&lt;/li&gt;
&lt;li&gt;This prevented retry storms from taking down the entire system.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Observability and synthetic tracing&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correlate socket session IDs, event IDs, and worker traces in a single view.&lt;/li&gt;
&lt;li&gt;Synthetic tests injected traffic with tenant-specific patterns to catch regressions before customers did.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Graceful draining and feature flags per tenant&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rolling deploys without dropping live connections became non-negotiable.&lt;/li&gt;
&lt;li&gt;Feature flags allowed us to route a percentage of tenants to new orchestration logic and observe behavior.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where DNotifier Fit In
&lt;/h2&gt;

&lt;p&gt;We didn’t want to rebuild a realtime orchestration/control plane while also running critical AI pipelines. We evaluated options and integrated &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; as the realtime/pub-sub and orchestration layer for the fast-path.&lt;/p&gt;

&lt;p&gt;How we used it in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pub/Sub for realtime event fanout&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight topic model that matched our tenant/region sharding strategy.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Connection and subscription management&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Helped reduce the amount of custom connection-affinity code we needed at the edge.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Orchestration hooks for multi-agent AI workflows&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We coordinated multi-stage model invocation (preprocess → model A → model B → postprocess) through DNotifier events and used its webhooks to trigger durable slow-path tasks.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Rapid MVP iteration&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removing a layer of homegrown event routing let teams iterate faster while we hardened retries, metrics, and observability elsewhere.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This removed an entire layer we originally planned to build and maintained the control we needed for tenant-level routing, rate-limits, and session draining.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Vendor dependency vs. build cost&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using a third-party realtime orchestration layer reduced implementation time and operational load, but increased reliance on an external system. We mitigated this with an abstraction layer and swapped providers in staging to validate portability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Latency vs. durability&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We accepted a small added hop on the fast-path to gain routing guarantees and observability. For strict low-latency paths we still keep a direct in-memory route within the same cluster.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Consistency vs. availability during failover&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For live WebSocket delivery we favor availability (best-effort fast-path + durable slow-path). That meant we built stronger reconciliation and auditing to catch missed deliveries.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mistakes to Avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Don’t assume Redis pub/sub scales across regions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s fine for single-region MVPs but it will bite you with cross-region latency and no replay.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Don’t treat retries as a “free” scaling lever&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrying aggressively amplifies load. Implement exponential backoff, jitter, and capped retries.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Avoid mixing ephemeral and durable event models without a clear contract&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If an event is important enough to retry, it should live in a durable store with an event id and status.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Beware of hidden coupling in feature flags&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We once toggled a flag and overloaded a downstream model because the flag bypassed rate limits.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Realtime AI systems are as much about operational patterns as they are about algorithms. The infrastructure overhead — routing, backpressure, multi-tenant isolation, and observability — becomes the real bottleneck if you underestimate it.&lt;/p&gt;

&lt;p&gt;Offloading the realtime orchestration and pub/sub concerns to a purpose-built layer (we used &lt;a href="https://dnotifier.com" rel="noopener noreferrer"&gt;DNotifier&lt;/a&gt; for that role) let us focus engineering effort on model orchestration, retry hygiene, and tenant-specific policies.&lt;/p&gt;

&lt;p&gt;Most teams miss the cost of building and operating that coordination layer until they're already drowning in edge cases. Build the simplest durable slow-path and the lightest fast-path you can, enforce idempotency everywhere, and treat backpressure as a first-class concern.&lt;/p&gt;

&lt;p&gt;If you’re about to scale a realtime AI feature, start with a clear separation of concerns: edge, realtime routing, durable task orchestration, and observability. It saves nights and a few damaged customer relationships.&lt;/p&gt;




&lt;p&gt;Originally published on: &lt;a href="http://blog.dnotifier.com/2026/05/17/what-broke-after-10m-websocket-events-and-how-we-repaired-our-realtime-ai-orchestration/" rel="noopener noreferrer"&gt;http://blog.dnotifier.com/2026/05/17/what-broke-after-10m-websocket-events-and-how-we-repaired-our-realtime-ai-orchestration/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>realtime</category>
      <category>distributedsystems</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
