DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

IoT

IoT, or the Internet of Things, is a technological field that makes it possible for users to connect devices and systems and exchange data over the internet. Through DZone's IoT resources, you'll learn about smart devices, sensors, networks, edge computing, and many other technologies — including those that are now part of the average person's daily life.

icon
Latest Premium Content
Trend Report
Database Systems
Database Systems
Refcard #375
Cloud-Native Application Security Patterns and Anti-Patterns
Cloud-Native Application Security Patterns and Anti-Patterns
Refcard #269
Getting Started With Data Quality
Getting Started With Data Quality

DZone's Featured IoT Resources

MQTT, Kafka, NATS, or Zenoh? Choosing Edge-to-Cloud Messaging by Traffic Pattern

MQTT, Kafka, NATS, or Zenoh? Choosing Edge-to-Cloud Messaging by Traffic Pattern

By Kai Wähner DZone Core CORE
Edge to cloud is not one integration problem. It is four: telemetry going up, control going down, sites syncing sideways, and data reaching people. Each has different physics. Most failed projects picked one technology for all four. Every enterprise with factories, stores, vehicles, hospitals, or devices faces the same architectural question. How does data move between the edge and the data center or cloud, in both directions, reliably, securely, and at acceptable cost? The vendor landscape answers with dozens of overlapping options: MQTT platforms, hyperscaler services, event streaming, event mesh, messaging fabrics, delivery platforms, and protocol proxies. This article structures the option space by traffic pattern instead of by product category, maps the vendor categories onto those patterns, and closes with a decision framework you can apply to your own architecture. The categories here sit alongside the wider integration landscape rather than inside it. For that broader map across event streaming, API, and batch, see the Data Integration Landscape 2026. What Does Edge-to-Cloud Communication Mean? Edge-to-cloud communication is the movement of data between distributed physical locations and centralized computing environments, in both directions, across networks the architect does not control. The word edge hides four very different tiers: The device edge means microcontrollers, sensors, and actuators with kilobytes of memory.The gateway edge means industrial PCs, vehicle computers, and protocol converters.The site edge means a factory, store, hospital, or ship with local compute and its own network boundary.The near edge means regional data centers close to many sites. A technology that fits one tier often fails at another. Edge to cloud splits into four traffic patterns: northbound telemetry, southbound control, site-to-site sync, and outbound delivery to people. The traffic crossing these tiers falls into four patterns: Northbound telemetry moves sensor readings, machine states, transactions, and logs from the edge toward central platforms for analytics, AI, and business systems.Southbound control moves commands, configuration, software updates, and increasingly AI models from central platforms down to machines and gateways.Site-to-site traffic synchronizes data between sites, between a site and a core data center, or between clouds.Outbound delivery pushes live data from central platforms to the applications people use: dashboards, mobile apps, and trading screens. Direction plus consumer type plus constraint determines the right technology. Vendor preference does not. Why Do Network Constraints Decide the Edge-to-Cloud Architecture? The network between edge and cloud is the one component you cannot refactor. Its properties dictate the architecture before any product evaluation starts. Connectivity is unreliable. Ships, vehicles, and remote sites go offline for hours or days. Any viable architecture is offline first: local operation continues, data buffers locally, and synchronization resumes when the link returns. This is why store and forward is the single most important capability on any edge evaluation checklist. Inbound connections are forbidden. Industrial sites, retail networks, and vehicle fleets sit behind NAT, firewalls, and cellular carriers. Security teams do not open inbound ports for messaging. Every serious edge technology therefore uses the same trick: the edge dials out. MQTT clients dial out to brokers. NATS leaf nodes dial out to hub clusters. Azure IoT Operations dials out from the factory to the cloud broker. Different stacks, identical answer, because the constraint is identical. Hardware is constrained and heterogeneous. An 8-bit microcontroller, a fanless gateway PC, and a site server need different footprints. Some technologies scale down to bare microcontrollers. Others assume a Kubernetes cluster. Matching footprint to tier is half the selection process. Footprint is not the only axis. In fixed installations like plants and warehouses, the device edge can stay thin, because the uplink is reliable and most intelligence lives upstream. In the field, agriculture, cranes, rural grid, remote or contested sites, the uplink is wireless and often degraded, saturated, expensive, or absent for days. There, the edge cannot just buffer and forward. It has to run enough local intelligence, pattern matching, image recognition, autonomous decisions, to operate correctly on its own and sync opportunistically when the link returns. That pushes compute onto the device tier for reasons that have nothing to do with protocol size, and it changes the pattern, not just the product. Data residency is now an architecture requirement, not a legal afterthought. European manufacturers increasingly must prove what data leaves the site, country, or jurisdiction. Topic design, routing rules, and retention policies become compliance controls. And one constraint is usually invented rather than measured: latency. Teams assert real-time requirements that the business case does not contain. A large share of edge traffic is perfectly fine as periodic batch over a metered link. Keep that thought. It returns in the site-to-site section. Northbound: How Does Telemetry Get from OT and Devices into the Core? Northbound telemetry is the pattern the industry knows best, and the one with the most settled consensus. At the machine level, OPC UA provides the semantic information model. It defines what a temperature, a batch, or a machine state means. MQTT provides the efficient transport, and Sparkplug adds topic structure, birth and death certificates, and state awareness on top of MQTT. The two standards stopped being rivals. OPC UA Pub/Sub over MQTT is the convergence point: OPC UA semantics carried over MQTT infrastructure. Edge gateways and industrial DataOps products, for example HighByte or Ignition with its MQTT modules, convert brownfield protocols like Modbus and S7 into that stack. The Unified Namespace (UNS) pattern then organizes all site data as a live, hierarchical topic structure on a central broker. I covered UNS design and its trade-offs in depth in Unified Namespace vs. Data Product in IT/OT for Industrial IoT and the broader MQTT market in MQTT Market Trends: Cloud, Unified Namespace, Sparkplug, Kafka Integration, so this section stays short. The real decision is the broker and its operating model. Self-managed platforms carry the northbound load for most industrial estates: HiveMQ and EMQX at the enterprise end, Mosquitto and NanoMQ where a lightweight or embedded footprint matters. They give you deployment control, protocol depth, and edge variants that run on gateways. Managed cloud services remove the operations burden and integrate natively with cloud analytics. The dividing line is usually sovereignty and site autonomy: if the broker must run inside the factory, on the ship, or in a specific jurisdiction, self-managed wins. If all sites have reliable connectivity and the data may leave, managed wins on cost of operations. The hyperscalers themselves tell an asymmetric story. Google retired Cloud IoT Core in 2023 and exited the category. AWS IoT Core remains the steady incumbent for managed device connectivity. Azure went furthest architecturally: Azure IoT Operations runs a distributed MQTT broker on Arc-enabled Kubernetes at the site edge and bridges it to the Event Grid MQTT broker in the cloud, which now supports Sparkplug natively. That is a symmetric edge plus cloud MQTT pair from a single vendor, and it is a new pattern. One hyperscaler retreated, one held, one doubled down. The lesson for architects: managed convenience is real, but so is the risk that a cloud provider deprecates your ingestion layer. The open standards underneath, MQTT and OPC UA, are the insurance policy. Choose products that speak them, and migration remains possible. Southbound and Outbound: How Do Data and Commands Flow Back to Machines and People? Almost all edge content covers ingestion. The return direction is harder, and it is where architectures break, because the return direction has two completely different consumers. Machines need commands and state. Request-response over pub/sub topics handles commands: reboot this gateway, close this valve, change this setpoint. Retained messages and device twins handle state: a device that reconnects must immediately learn its desired configuration without waiting for the next command. Fleet-wide rollout needs staged delivery, and the payloads keep growing. Configuration files became firmware images, and firmware images are becoming AI models. Shipping a quantized model to ten thousand gateways is a southbound data movement problem, not an MLOps footnote. The same fabric increasingly carries traffic for agents at the edge: AI agents that perceive local data, act locally, and coordinate through the messaging layer. NATS and the MQTT platforms are both positioning for exactly this workload. People need the current picture. A plant manager opening a dashboard, an operator reconnecting after a network drop, and a trader loading a screen mid-session all have the same requirement: current state on connect, then live updates. A log is not a user interface. Machines just consume the stream. People do not. This is the last-mile delivery problem, and it has its own vendor category: Lightstreamer, Ably, and PubNub sit between the central platform and many concurrent browsers and mobile apps, handling fan-out, per-client throttling, and entitlement checks. The category is maturing fast. For instance, Lightstreamer's Kafka Connector 2.0, released in July 2026, moved snapshot management into the connector itself, so every reconnecting client receives materialized state followed by the live stream. Delivery to humans deserves a dedicated article. Here it earns its place as the fourth traffic pattern that most edge architectures forget until the first user complains. Site-to-Site: How Do Sites, Data Centers, and Clouds Stay in Sync? The third direction is sideways: keeping data consistent between many sites and one core, or between multiple clouds. For durable event streams, Kafka-style replication is the default. Open source MirrorMaker 2 or vendor-specific cluster linking copies topics between an edge cluster and the central cluster, preserving ordering and history. Apache Kafka is the open-source option; Confluent, Amazon MSK, Aiven, and other solutions are the managed ones. This suits sites large enough to operate a streaming cluster, such as a factory with local analytics that also feeds the global platform. For thousands of small sites, the streaming cluster per site model collapses under its own operational weight. This is where NATS is architecturally distinct rather than just another broker. The entire server is a single small binary with no external dependencies. Each store, vehicle, or clinic runs a leaf node that dials out to the central cluster, keeps serving local applications when the WAN drops, and uses JetStream mirroring to synchronize persisted streams when connectivity returns. Retail chains run this pattern across thousands of locations. The same design serves both the intermittent case, hours or days offline with a bulk sync on reconnect, and the scheduled-batch case where sites replicate on a timer rather than continuously. Its own maintainers warn against one trap: do not stretch a single stream cluster across unstable edge links, because the cluster's consensus breaks every time the network does. Instead, let each site persist its data locally and keep serving through an outage, then mirror to the center asynchronously when the link returns. For enterprises whose sites run applications rather than device fleets, an event mesh covers the same ground at the application layer. Solace links its brokers across data centers and clouds so an event published anywhere reaches any interested subscriber, with topic routing and governance built in. It is the natural fit when the endpoints are SAP, mainframes, and microservices rather than sensors. And a large share of site-to-site traffic does not need streaming, even if streaming is often the stronger long-term architecture. Nightly file synchronization, batch uploads over metered links, and change data capture from edge databases remain perfectly valid when there is no real-time requirement. This is especially true when the existing OT and IT systems on both ends are batch-oriented anyway, and no business case justifies the cost and effort of making them real time. Real time is a requirement, not a default. Stream when you need fresh data, or when you build greenfield and carry no legacy batch systems to preserve. An architecture that streams everything pays streaming costs for batch problems. Which Category Serves Which Edge to Cloud Pattern? Seven vendor categories map onto the four patterns. No single category covers all of them, and messaging fabrics, event mesh, and protocol proxies deliberately span several. No single vendor covers every direction. Seven categories divide the field, and the real picture is that some sit in one pattern while others deliberately span several. MQTT platforms (EMQX, HiveMQ, Mosquitto, NanoMQ) serve both northbound telemetry and southbound control, because MQTT is bidirectional by design. Hyperscaler services (AWS IoT Core, Azure IoT Operations) do the same for the managed-cloud case, ingesting telemetry and pushing desired state through device twins. Event streaming (Apache Kafka, Confluent, Aiven, and more in the data streaming landscape) owns site-to-site replication. Last-mile delivery(Ably, Lightstreamer, PubNub) owns outbound delivery to people, and it is the only pattern with a category built solely for it. Three categories span multiple patterns. An event mesh (Solace) routes site-to-site and out to applications. Messaging fabrics (NATS, Zenoh) carry northbound, southbound, and site-to-site in a single fabric. Protocol proxies (Zilla) translate across all four, replacing several specialized components with one layer. The underlying distinction is worth stating plainly: a protocol standard is not a deployment architecture. MQTT standardizes the wire, which is why so many products speak it and your devices stay portable. NATS and Zenoh standardize the topology, which reduces moving parts and increases commitment. Zenoh, born from DDS research and adopted by automotive initiatives including General Motors' uProtocol and by the ROS 2 robotics ecosystem, goes furthest: it routes named data along the shortest path between producer and consumer, aiming to make the cloud versus edge placement debate irrelevant. These spanning options are not equivalent. A fabric like NATS or Zenoh reduces moving parts and unifies security by being one technology end to end, but that reach is also the lock-in: the more it carries, the more expensive it is to leave. A protocol proxy like Zilla does the opposite. It spans the patterns by translating between existing technologies, which keeps your exit options open at the cost of another component in the path. The right choice depends on how many patterns you actually need and how much lock-in you can accept, not on which vendor markets hardest. How to Choose: Five Questions That Pick Your Edge-to-Cloud Architecture Product evaluations start too late. Answer five questions first, and the shortlist mostly writes itself. Five-question decision framework for choosing an edge-to-cloud architecture, from consumer type to data residency Who consumes the data, machines or people? People need current state on connect, then live updates, which means a last-mile delivery layer over the backbone. Machines just consume the stream.Does this flow actually need real time? Measure before you architect. If a fifteen-minute batch satisfies the business case, use file sync or change data capture. Stream when you need fresh data, because streaming infrastructure you did not need is the most expensive kind.What is the most constrained node in the path? A microcontroller means MQTT or Zenoh, the two with clients small enough for the device itself, not a JVM. A gateway opens the field to lightweight NATS or full brokers, and a site server adds event meshes or a small streaming cluster.How many sites, and can each one operate a cluster? A few large sites with local analytics justify edge Kafka clusters with MirrorMaker or cluster linking. Hundreds or thousands of small sites demand hub-and-spoke: NATS leaf nodes or hierarchical MQTT bridges, with store and forward at every spoke. Enterprises whose sites run applications rather than devices fit an event mesh.Where must the data live? If residency or sovereignty rules apply, the broker runs on site or in jurisdiction, self-managed, and routing policy becomes a compliance control. If data may leave and connectivity is solid, managed cloud services win on operations cost. Two checks apply on almost every branch, at every step. The edge must dial out and never accept inbound connections to the site. And local operation must survive offline, with a buffer sized deliberately, not discovered in the first outage. Five questions, four patterns, one map. The technologies then sort themselves into it. Moving Data Is Not Automating the Business Every pattern and category in this article solves the same problem: moving data between edge, data center, and cloud. That movement is necessary but not sufficient. When telemetry arrives, something must decide what happens next: trigger the maintenance workflow, roll back the failed firmware deployment, replicate the dataset, open the ticket, retrain the model. Deciding what happens next is workflow orchestration. It spans the same edge-to-cloud boundary as the data movement beneath it. Data integration moves the events. Orchestration, with the process intelligence to see how those flows actually run, decides what the business does about them. And increasingly, agentic AI acts on those decisions at the edge. These are not three separate topics. They are one stack, and edge to cloud is where they meet the physical world. Architectures that move data and improvise everything above it end up with the automation logic scattered across broker plugins, cron jobs, and cloud functions. That is the integration spaghetti this whole discipline set out to remove. Edge to cloud is not one problem. It is four. Architect for the pattern, not the product. More
How to Migrate From C/C++ to Rust: A Practical Guide for Embedded IoT Systems

How to Migrate From C/C++ to Rust: A Practical Guide for Embedded IoT Systems

By Andrew Davies
Embedded and IoT devices operate in environments where every kilobyte of memory and every millisecond of response time matters. Yet most of them still rely on C or C++, languages powerful enough for low-level control but notorious for memory-safety flaws that can crash systems or expose them to security vulnerabilities. The issue is so widespread that around 70% of Microsoft’s and Google’s reported vulnerabilities stem from memory-safety issues. For connected devices running critical operations, such instability isn’t an option. However, a structured C++ to Rust migration addresses the root cause by replacing unsafe memory handling with compile-time guarantees and predictable real-time performance. Embedded environments leave little room for trial and error; therefore, experience and a clear roadmap make a big difference. For this purpose, companies often work with teams skilled in Rust development services and familiar with embedded software development. With the right expertise, you can introduce new Rust components gradually and safely without interruptions to the existing IoT ecosystem. Now, let’s discover how to migrate from C/C++ to Rust, review the migration challenges and best practices to mitigate them, and analyze a success story of practical Rust migration for embedded systems. Why Consider Migrating From C/C++ to Rust? Modern embedded systems, especially IoT-based medical devices, put heavy pressure on safety, energy use, and long-term maintenance. Rust handles these demands better than traditional C or C++ thanks to its built-in memory safety, reliable concurrency model, and predictable real-time behavior. When organizations consider a C++ to Rust migration, these advantages quickly become deciding factors for modernizing connected devices. They also translate into more stable products and lower life cycle costs: Reduced security risks: Rust’s memory safety drastically lowers vulnerabilities, meaning fewer patches and less downtime for IoT systems.Lower long-term maintenance costs: Rust reduces bugs that emerge later in production, leading to fewer expensive fixes after deployment.Improved reliability: With Rust, IoT devices crash less often, which means more uptime and fewer disruptions for end-users.Better performance: Rust’s efficiency can lead to lower energy consumption, extending the life of battery-powered IoT devices and reducing energy costs.Faster time-to-market for updates: Rust’s safe concurrency allows quicker development of new features without compromising stability, which means you can roll out improvements to your IoT solutions faster.Future-proof technology: Rust’s growing popularity means a sustainable ecosystem, which ensures that your IoT product stays modern and well-supported for years to come.Increased development velocity: Rust reduces debugging time and makes the code easier to reason about, speeding up onboarding and increasing overall developer productivity. Three Common Myths About Rust Migration Many organizations hesitate to begin migrating embedded systems from С or C++ to Rust because they expect major risks or disruptions. In reality, most of these concerns stem from common misconceptions rather than technical limitations in embedded software development. Understanding what Rust migration actually involves helps teams make confident, well-informed decisions. Let’s review the three most common misconceptions. Myth 1: “We’ll Have to Rewrite Everything” You don’t need a full rewrite to begin a C++ to Rust migration. Many teams start small, moving one or two isolated modules that bring the most maintenance pain. Using the Foreign Function Interface (FFI), Rust can work alongside C or C++ within the same firmware. This feature makes it possible to modernize gradually while the rest of the system stays live. Myth 2: “Switching to Rust Will Interrupt Delivery” Migration can happen without stopping production. With a structured approach, Rust modules are added one by one while existing CI/CD pipelines continue to run. Each new piece is tested, deployed, and benchmarked before the next one is introduced. The development cycle continues as usual; only the language inside changes. Myth 3: “We’ll Have to Replace the Entire Engineering Team” Most C or C++ developers adapt to Rust faster than expected. The languages share similar low-level logic, which makes the learning curve manageable with proper mentoring and review. Once trained, the same team can handle both Rust and C++, maintaining delivery speed while building long-term expertise. Three Ways of C/C++ to Rust Migration There’s no one-size-fits-all approach to C++ to Rust migration. The right strategy depends on how your system works today, how critical uptime is, and what level of modernization you’re aiming for. When adopting Rust for IoT and embedded systems, companies typically choose one of three paths: gradual integration, full rewrite, or hybrid migration. 1. Gradual Integration This path is ideal for safety-critical or continuously running devices. Instead of rewriting everything, the developers introduce Rust gradually — one module at a time. Typical starting points include telemetry handlers, utility modules, or background services that can be tested in isolation. The existing C/C++ software keeps running while new Rust components are integrated and validated. Over time, as more modules are proven stable, Rust takes over a larger share of functionality. 2. Full Rewrite If you’re launching a new product or phasing out outdated firmware, a full rewrite may be the most efficient route. The development starts with Rust from day one. It covers firmware logic, communication layers, and testing infrastructure. This scenario removes legacy constraints entirely and lets your team build clean architectures without legacy dependencies, design for memory safety from the start, and use Rust’s concurrency model to its full advantage. A full rewrite requires a skilled team, proven toolchains, and time for onboarding, but it also gives you complete control over the system’s design. Yalantis supports such transformations through end-to-end Internet of Things solutions, helping businesses develop secure, scalable, and future-ready connected products. 3. Hybrid Approach Many embedded systems can’t be fully rewritten due to vendor SDKs, licensed components, or hardware dependencies. In those cases, Rust and C/C++ coexist. Engineers connect both through FFI, so each language can do what it does best. C++ handles hardware-level operations, while Rust manages business logic, safety-critical processes, or communication layers. This model works particularly well for medical devices, industrial equipment, and long-lifecycle IoT platforms, where reliability and compliance matter just as much as modernization speed. Challenges and Best Practices by Yalantis for C/C++ to Rust Migration Before starting a full-scale migration, it’s important to understand the technical and architectural risks involved. Each challenge that appears during the embedded C++ to Rust migration can be handled through structured engineering practices. Below is an overview of key challenges in migrating embedded firmware from C++ to Rust and the Rust migration best practices Yalantis uses to keep modernization predictable and low-risk. Challenge 1: Maintaining Compatibility With Existing C/C++ Code Legacy firmware often has C++ modules woven tightly together. You can’t rewrite everything at once without risking device instability or unexpected regressions. Challenge 2: Operating Under Hardware and Microcontroller Limitations Most embedded devices run on minimal RAM, limited storage, and low CPU frequencies. A rushed migration can overload the hardware or increase latency. Challenge 3: Ensuring Deterministic Behavior in Real-Time Systems IoT and embedded applications often have strict timing and reliability requirements. Even slight delays in execution can affect safety, user experience, or device coordination. Challenge 4: Integrating With External Libraries and APIs Embedded firmware relies on vendor drivers, communication stacks, and low-level APIs. Poor integration planning can cause instability or break device compatibility. Conclusion Modernizing embedded and IoT systems requires predictable performance, strong security guarantees, and code that stays maintainable as the product evolves. Traditional C/C++ firmware often struggles with these demands. Rust solves many of these challenges upfront with built-in memory safety, reliable concurrency, deterministic execution, and a modern development ecosystem that reduces defects and speeds up delivery. A well-planned C/C++ to Rust migration strengthens product stability, lowers lifecycle costs, and gives you a foundation that scales with new device architectures and connectivity needs. More
When One Docker Swarm Replica Became Unreachable Over an Overlay Network: A Production Case With Traefik
When One Docker Swarm Replica Became Unreachable Over an Overlay Network: A Production Case With Traefik
By Denis Tiumentsev
Documentation Debt Is the Real Risk in Long-Lived Network Infrastructure
Documentation Debt Is the Real Risk in Long-Lived Network Infrastructure
By Savni Sandbhor
Building IoT Time-Series Applications With Java and Apache IoTDB
Building IoT Time-Series Applications With Java and Apache IoTDB
By Otavio Santana DZone Core CORE
Beyond Clicking Buttons: Build a Browser Agent That Verifies Its Results With Playwright MCP
Beyond Clicking Buttons: Build a Browser Agent That Verifies Its Results With Playwright MCP

Browser agents become useful when they can do more than reach the right page and trigger the right control. A click is only an attempted action; it is not proof that a business operation completed. A form can submit while validation fails, a checkout button can respond while the API returns an error, and a success-looking route can render stale state. Playwright MCP is well suited to closing that gap because it exposes browser interaction through structured accessibility snapshots and adds explicit testing tools for checking visible elements, text, lists, and form values. The result is an agent loop that can treat verification as a first-class phase rather than as an optimistic interpretation of the previous action. An Action Is Not a Result The central design rule is simple: every state-changing action should have a postcondition. In an ordinary browser automation script, success is often inferred from the absence of an exception. That standard is too weak for an autonomous agent. Playwright MCP interaction tools such as browser_click operate on element references taken from accessibility snapshots, and most actions return an updated snapshot after triggered browser work settles. That makes the post-action page state immediately available, but the controller still has to decide what evidence counts as success. A useful contract separates intent, action, and evidence. For a task such as submitting an order, the action is a click on the final submission control. The evidence might be a visible confirmation heading plus an order identifier. The agent should not report completion until those conditions are independently checked. With the testing capability enabled, Playwright MCP provides browser_verify_element_visible, browser_verify_text_visible, browser_verify_list_visible, and browser_verify_value. Verification calls return Done on success and an error on failure, which creates a clean boundary between a browser action and a verified outcome. A minimal controller can therefore make the verification step explicit: TypeScript await client.callTool({ name: "browser_click", arguments: { target: submitRef } }); await client.callTool({ name: "browser_wait_for", arguments: { text: "Order confirmed" } }); const proof = await client.callTool({ name: "browser_verify_element_visible", arguments: { role: "heading", accessibleName: "Order confirmed" } }); if (proof.isError) { throw new Error("Order submission could not be verified"); } The important property is not the specific wrapper around callTool; it is the control flow. Action and verification are different operations, and a failed verifier changes the task status from “completed” to “unconfirmed.” browser_wait_for is appropriate when a specific asynchronous transition must finish, while Playwright MCP already waits for triggered navigation and network activity after most actions. Fixed sleeps should remain a last resort because the server supports waiting for text to appear or disappear directly. Verification Should Match the Business Outcome A reliable verifier checks the state that matters to the task rather than a convenient visual change. A button becoming disabled proves only that the button changed. A toast saying “Saved” is stronger, but still may not prove persistence if the application updates optimistically. Browser-level evidence becomes stronger when multiple independent signals agree: semantic UI state, the resulting page structure, and relevant network activity. Playwright MCP exposes each of these forms of evidence through snapshots, verification tools, and network inspection. Playwright MCP exposes network inspection through browser_network_requests and browser_network_request, allowing an agent to locate a relevant request and inspect its details. Console messages are also available through the core browser_console_messages tool. Those channels are useful when a task appears successful in the DOM while a background request fails or the page emits an uncaught error. Network evidence should still be tied to application semantics; an HTTP response by itself does not establish that the intended record contains the correct data. For a profile update, the strongest browser-side check may be a round trip: submit the change, wait for the completion signal, navigate away or reload, then verify the field value from the newly rendered state. browser_verify_value supports textboxes, checkboxes, radios, comboboxes, and sliders, so persistence checks can stay semantic instead of scraping raw HTML. TypeScript await client.callTool({ name: "browser_verify_value", arguments: { type: "textbox", element: "Display name", target: displayNameRef, value: expectedName } }); This pattern is especially important for agentic workflows because planning logic can be probabilistic while verification can remain deterministic. The model may choose among several valid ways to reach a form, but the acceptance criterion can still be exact: a heading exists, a field equals an expected value, a list contains required entries, or confirmation text is visible. Playwright MCP’s verification tools are designed around those concrete browser states. Accessibility Snapshots Make the Feedback Loop Precise Playwright MCP uses accessibility snapshots as the primary representation for agent interaction. A snapshot contains roles, accessible names, text, and element references used by subsequent tool calls. This is materially different from relying on screenshots as the main control surface. Screenshots remain valuable for visual diagnostics, but the MCP documentation explicitly directs actions toward snapshots rather than screenshot coordinates. That distinction improves verification quality. A semantic check such as “heading named Order confirmed is visible” is less ambiguous than a model deciding whether a collection of pixels resembles a success page. It also aligns the agent’s evidence with the same roles and names used by Playwright locators. When only part of a large page matters, browser_find can search the accessibility snapshot and return matching nodes with local context, reducing the need to repeatedly consume the full tree. Screenshots still have a place when the requirement is inherently visual, such as confirming layout, clipping, or rendering. For correctness of transactional browser work, however, semantic evidence should dominate. Tracing can then provide failure forensics rather than primary success criteria. With the devtools capability, Playwright MCP can record traces containing DOM snapshots, screenshots, network activity, console logs, and timing, making an unverified or failed run reproducible after the fact. Successful Agent Runs Can Become Regression Tests Verification becomes more valuable when it survives beyond a single agent session. Playwright MCP’s testing capability records matching expect(...) code for verification tools, and action responses can include generated Playwright code. The documentation explicitly shows an exploratory sequence being assembled into a conventional Playwright test. That creates a productive path from autonomous exploration to deterministic regression coverage. A verified flow can therefore graduate into a compact test instead of remaining hidden inside an agent transcript: TypeScript test("submits an order", async ({ page }) => { await page.getByRole("button", { name: "Place order" }).click(); await expect( page.getByRole("heading", { name: "Order confirmed" }) ).toBeVisible(); await expect( page.getByText(expectedOrderNumber) ).toBeVisible(); }); The same principle should shape production configuration. Only required capabilities should be exposed, isolated sessions should be preferred for repeatable runs, and origin restrictions can reduce accidental navigation. Playwright MCP supports capability selection, isolated profiles, allowed and blocked origins, secrets redaction, and configurable timeouts. Its documentation also warns that origin controls and secret handling are convenience defenses rather than security boundaries, so client-level permissions remain necessary when an agent can perform consequential actions. Conclusion A browser agent becomes dependable only when completion means more than “the click happened.” Playwright MCP provides the pieces required for a verification-centered design: structured accessibility snapshots for precise targeting, explicit verification tools for semantic postconditions, waiting primitives for asynchronous transitions, network and console evidence for deeper diagnosis, and traces for failed-run analysis. The strongest implementation treats every consequential action as a hypothesis that must be proven by observable browser state. That shift turns browser automation from a sequence of hopeful interactions into a controlled execution loop whose results can be checked, explained, and eventually converted into durable Playwright regression tests.

By Akhil Madineni DZone Core CORE
Jakarta Batch in Practice: Reliable Chunk-Oriented Processing for Enterprise Workloads
Jakarta Batch in Practice: Reliable Chunk-Oriented Processing for Enterprise Workloads

Batch processing remains vital because many business operations aren't suited to interactive requests. Tasks such as recalculating prices, reconciling transactions, migrating records, generating reports, processing invoices, reclassifying customers, or applying rules across millions of records may require considerable time. Handling these as standard requests leads to fragile systems, increased user wait times, frequent timeouts, challenging retries, and possible data inconsistencies. A batch model handles large workloads predictably, incrementally, and with control over progress and recovery. Rather than processing a massive operation as a single loop, batch processing uses jobs, steps, chunks, checkpoints, filtering, and restartability. This approach separates long-running data tasks from the user experience while delivering a structured execution model. In this article, we will focus on Jakarta Batch and examine its sustained relevance for modern enterprise applications. Why Batch Processing Still Matters in Enterprise Systems Modern applications offer various methods for background processing, such as message queues, event-driven architectures, schedulers, reactive pipelines, and distributed stream-processing platforms. While each addresses specific needs, batch processing is most effective when operations have a defined start and end, involve a known or discoverable dataset, and require controlled execution, progress tracking, restartability, or periodic processing. Batch processing remains essential in enterprise systems. Workloads such as financial reconciliation, billing, payroll, reporting, data migration, regulatory processing, catalog updates, and large-scale reclassification are still prevalent. In these scenarios, the priority is to process large volumes of work safely and predictably, rather than responding to individual events quickly. Batch provides a model specifically designed for these requirements. How Jakarta Batch Works Jakarta Batch organizes background processing into jobs and steps. A job defines the overall batch operation, while each step represents a specific stage. In chunk-oriented processing, a step follows a simple pipeline: read, process, write, and repeat until it processes all input. The Jakarta Batch runtime manages this lifecycle so application code can focus on reading, transforming, and persisting data. A job is the top-level unit of execution and represents a complete business operation, such as importing records, recalculating customer classifications, processing invoices, or reconciling transactions. Jobs can accept parameters at startup, allowing the same batch definition to run with different inputs or business rules. A job consists of one or more steps, each representing a distinct phase of the workload. Simple jobs may have a single step, while complex processes can use multiple steps in sequence, such as importing data, validating it, and generating a final report. Within a chunk-oriented step, the ItemReader supplies data to the runtime one item at a time, from sources such as a database or file. The reader only retrieves the next item and does not need to know how it will be processed or persisted.The ItemProcessor receives each item and applies business rules, such as validation, transformation, classification, enrichment, or filtering. It may return a modified item or null if the item should be excluded from writing.The ItemWriter receives processed items and persists or exports them. Unlike the reader and processor, which handle items individually, the writer typically receives a group of items from the current chunk. This enables more efficient database or bulk operations. Jakarta Batch adds features around this pipeline to support enterprise workloads. The runtime manages chunk boundaries, transactions, checkpoints, execution status, failures, and restart behavior. Chunk size determines how much work is grouped before a write and checkpoint, making it a key parameter for balancing throughput, memory usage, database cost, and recovery. The core model is straightforward: Job → Step → Read → Process → Write → Repeat Jakarta Batch keeps the business pipeline simple while the runtime manages the execution mechanics needed for reliable, long-running data processing. The Sample: Customer Segmentation with Jakarta Batch This example demonstrates the Jakarta Batch model using an e-commerce customer segmentation scenario. Customers are assigned to tiers such as Bronze, Silver, Gold, and Platinum based on configurable spending thresholds. When thresholds change, the application reevaluates the customer base and updates only customers whose classification has changed. The full application includes MongoDB integration, a Jakarta Faces UI, a preview workflow, validation, and supporting services. The complete source code is available at https://github.com/soujava/mongodb-jakarta-batch. This section focuses on the classes directly involved in Jakarta Batch execution. Starting the Batch Job The application initiates the batch process through CustomerSegmentationService. Unlike the reader, processor, and writer, this class is not a batch artifact. Instead, it is an application service that retrieves Jakarta Batch’s JobOperator from BatchRuntime to start and monitor job executions. Java @ApplicationScoped public class CustomerSegmentationService { public static final String JOB_NAME = "customer-segmentation"; private volatile CustomerSegmentationPolicy currentPolicy; // initialization and status methods omitted public long start(CustomerSegmentationPolicy policy) { if (isRunning()) { throw new IllegalStateException( "A customer segmentation batch is already running"); } Properties parameters = new Properties(); parameters.setProperty( CustomerSegmentationPolicy.JOB_PARAMETER, policy.toJson()); long executionId = BatchRuntime.getJobOperator() .start(JOB_NAME, parameters); currentPolicy = policy; return executionId; } public boolean isRunning() { // implementation omitted } } The key API here is JobOperator, which Jakarta Batch provides as the interface for starting, stopping, restarting, and inspecting jobs. In this example, the segmentation policy is serialized into the job parameters to ensure each execution gets the correct business rules. Reading the Input The first batch artifact, CustomerItemReader, extends Jakarta Batch’s AbstractItemReader to implement a chunk-oriented reader. Java @Named("customerItemReader") @Dependent public class CustomerItemReader extends AbstractItemReader { @Inject private CustomerRepository customerRepository; private List<Customer> customers = List.of(); private int nextIndex; @Override public void open(Serializable checkpoint) { try (Stream<Customer> customerStream = customerRepository.findAll()) { customers = customerStream .sorted(Comparator.comparing(Customer::getId)) .toList(); } nextIndex = checkpoint instanceof Integer index ? index : 0; } @Override public Customer readItem() { if (nextIndex >= customers.size()) { return null; } return customers.get(nextIndex++); } @Override public Serializable checkpointInfo() { return nextIndex; } } These methods are part of the Jakarta Batch reader lifecycle defined by AbstractItemReader. open() prepares the reader and accepts a previous checkpoint if available. readItem() provides the next item to the runtime; returning null indicates there is no more input. checkpointInfo() reports the reader’s current position for checkpointing. For simplicity, this sample loads customers into memory. For larger workloads, the implementation might use pagination or a MongoDB cursor without changing the Jakarta Batch model. Processing Each Customer The next artifact implements Jakarta Batch’s ItemProcessor interface. Java @Named("customerTierProcessor") @Dependent public class CustomerTierProcessor implements ItemProcessor { @Inject @BatchProperty( name = CustomerSegmentationPolicy.JOB_PARAMETER) private String thresholdsJson; private CustomerSegmentationPolicy policy; @PostConstruct void initialize() { policy = CustomerSegmentationPolicy.fromJson( thresholdsJson); } @Override public Customer processItem(Object item) { if (!(item instanceof Customer customer)) { throw new IllegalArgumentException( "Expected a Customer item"); } CustomerTier calculatedTier = policy.tierFor(customer.getTotalSpent()); if (calculatedTier == customer.getTier()) { return null; } return Customer.builder() .id(customer.getId()) .name(customer.getName()) .totalSpent(customer.getTotalSpent()) .tier(calculatedTier) .build(); } } Here the Jakarta Batch contract is explicit: ItemProcessor defines processItem(). The runtime calls that method for every item produced by the reader. The processor applies the segmentation rule and either returns the transformed customer or null. Returning null has a specific meaning in Jakarta Batch: the item is filtered and does not continue to the writer. The @BatchProperty is also part of the Batch integration. It receives the thresholds property defined for this job execution, allowing the processor to reconstruct the CustomerSegmentationPolicy before processing begins. Writing the Results The final artifact extends AbstractItemWriter, Jakarta Batch’s base implementation for writing a chunk. Java @Named("customerItemWriter") @Dependent public class CustomerItemWriter extends AbstractItemWriter { @Inject private CustomerRepository customerRepository; @Override public void writeItems(List<Object> items) { List<Customer> customers = items.stream() .map(this::toCustomer) .toList(); customerRepository.saveAll(customers); } private Customer toCustomer(Object item) { if (item instanceof Customer customer) { return customer; } throw new IllegalArgumentException( "Expected a Customer item"); } } writeItems() is defined by the Jakarta Batch writer contract inherited from AbstractItemWriter. Unlike the processor, which receives one item at a time, the writer receives a collection of processed items. In this case, the collection contains only customers whose classification changed, as the processor has already filtered the others. At this point, the Java components of the pipeline are as follows: Plain Text CustomerItemReader extends AbstractItemReader ↓ CustomerTierProcessor implements ItemProcessor ↓ CustomerItemWriter extends AbstractItemWriter These types are what connect the application code to the Jakarta Batch runtime. Connecting the Artifacts With JSL The Java classes define the behavior, but Jakarta Batch requires explicit mapping of the reader, processor, and writer to each job. This orchestration is described in JSL: XML <?xml version="1.0" encoding="UTF-8"?> <job id="customer-segmentation" xmlns="https://jakarta.ee/xml/ns/jakartaee" version="2.0"> <step id="recalculate-customer-tiers"> <chunk item-count="20"> <reader ref="customerItemReader"/> <processor ref="customerTierProcessor"> <properties> <property name="thresholds" value="#{jobParameters['thresholds']}"/> </properties> </processor> <writer ref="customerItemWriter"/> </chunk> </step> </job> The ref values correspond directly to the names declared with @Named in the Java classes: Java @Named("customerItemReader") @Named("customerTierProcessor") @Named("customerItemWriter") The XML therefore tells the Jakarta Batch runtime: for this step, use this reader, then this processor, and finally this writer. It also maps the thresholds job parameter into the processor property. The item-count="20" sets the chunk size for this sample. Jakarta Batch coordinates reading and processing, periodically invoking the writer according to the chunk lifecycle and establishing transaction and checkpoint boundaries. The value 20 is for demonstration; real applications should tune chunk size based on processing cost, database behavior, transaction size, throughput, and recovery requirements. This structure is recommended for the article: present the class declaration first, then describe the lifecycle methods inherited from or required by Jakarta Batch. This approach helps the sample teach the API rather than simply presenting isolated methods. Conclusion Jakarta Batch is valuable because it transforms large-scale data processing into a structured execution model, eliminating the need for custom loops and ad hoc background logic. By separating reading, processing, and writing, and introducing runtime concepts such as jobs, steps, checkpoints, restartability, and chunk-oriented execution, it provides enterprise applications with a predictable approach to handling workloads involving thousands or millions of records. This allows implementations to focus on business logic, while the Batch runtime manages repetitive execution concerns, making the model easier to understand, optimize, and scale as workloads increase.

By Otavio Santana DZone Core CORE
Securing Branch Networks With Firewalls, VPNs, IDS/IPS, and Identity-Based Access
Securing Branch Networks With Firewalls, VPNs, IDS/IPS, and Identity-Based Access

Branch networks no longer behave like quiet extensions of a single headquarters LAN. They terminate local user traffic, break out directly to the internet for SaaS, maintain persistent connections back to core systems, and increasingly host devices that are operationally important even when central resources are unavailable. NIST notes that the enterprise network landscape has shifted because of cloud services, geographic dispersion, and changes in application design, while zero trust guidance emphasizes that network location is no longer the primary signal of trust. In practice, that means a branch cannot be secured by treating the site-to-site tunnel as a blanket trust boundary. The branch edge has to make explicit policy decisions about which flows are allowed, which flows are encrypted, which flows are inspected, and which identities are entitled to touch which resources. Beyond the Old Perimeter The older perimeter model assumed that most meaningful risk arrived from outside the network and that internal traffic was comparatively trustworthy. That assumption breaks down quickly in distributed environments. NIST’s current network guidance explicitly calls out the limitations of perimeter-centric protection and VPN-centric access in environments that include cloud services, remote users, and branch offices, while NSA’s zero trust guidance frames lateral movement as a primary post-compromise technique that segmentation and granular policy are meant to contain. A modern branch design therefore needs layered control points close to the resource and close to the user, not just a tunnel back to a core firewall. That shift also changes how edge devices are treated operationally. Branch firewalls, VPN gateways, and routers are no longer simple plumbing. They are security control planes, and they are common targets. CISA issued Binding Operational Directive 23-02 specifically to reduce the risk from internet-exposed management interfaces, and NSA recommends encrypted administration, ACL-restricted management access, and dedicated management segments rather than broad reachability from production networks. Securing the branch therefore starts with the idea that the branch edge itself must be hardened, isolated, and observable before it is entrusted to enforce policy for anything else. Firewalls Define Intent A branch firewall is most effective when it expresses business intent instead of accumulating ad hoc port exceptions. NIST’s firewall guidance is still the right mental model: block inbound and outbound traffic unless it is expressly permitted, use stateful inspection to track valid sessions, and apply egress filtering so that spoofed or unexpected source traffic cannot leave the site. Where application awareness is needed, NIST also notes that application-proxy gateways can inspect protocol content and, in some cases, decrypt and re-encrypt selected traffic before forwarding it. That combination turns the firewall from a coarse packet filter into a policy engine that knows the difference between permitted business traffic and merely possible traffic. A concise nftables policy for a small branch can be deliberately narrow: Plain Text table inet filter { chain forward { type filter hook forward priority 0; policy drop; ct state established,related accept iifname "lan" oifname "wan" ip saddr 10.20.30.0/24 ip daddr 10.10.0.0/16 tcp dport 443 accept iifname "lan" oifname "wan" ip saddr 10.20.30.0/24 udp dport 53 accept iifname "lan" oifname "wan" ip saddr 10.20.30.0/24 tcp dport { 80, 443 } accept } } The shape of that ruleset matters more than the exact addresses. The first line admits only established or related traffic, which keeps return paths fast without making the policy permissive. The next rule allows a very specific branch-to-core application path over HTTPS. DNS is explicitly separated because name resolution is usually treated as infrastructure rather than open internet access. The final rule allows only web egress from the branch subnet, and the chain-wide policy drop turns every other flow into an intentional denial instead of an accidental omission. That aligns with NIST’s deny-by-default and egress-filtering guidance, and it scales far better than a firewall that starts from “allow any” and slowly adds patches. VPNs Protect the Path VPNs remain essential in branch networking, but their role is precise: protect traffic in transit across untrusted transport, not grant broad implied trust to the attached network. NIST’s IPsec guidance identifies gateway-to-gateway VPNs as the common model for linking a branch office to headquarters and notes that the model is operationally simple because it is largely transparent to end users. The same guidance recommends IKEv2 over IKEv1 because IKEv2 is simpler, faster, and more secure, and it lists modern algorithm choices such as AES-GCM and SHA-2 families as recommended options. It also states that tunnel mode is used for gateway-to-gateway deployments and that perfect forward secrecy should be used when resources allow. A stripped-down strongSwan configuration shows the right shape for a branch-to-core tunnel: Plain Text connections { branch-hq { version = 2 remote_addrs = 198.51.100.10 proposals = aes256gcm16-prfsha384-ecp384 local { auth = pubkey; certs = branch-gw.pem; id = branch-gw.example } remote { auth = pubkey; id = hq-gw.example } children { corp { local_ts = 10.20.30.0/24 remote_ts = 10.10.0.0/16 esp_proposals = aes256gcm16-ecp384 rekey_time = 50m start_action = trap } } dpd_delay = 30s } } The important details are the constrained traffic selectors and the modern cryptographic profile. local_ts and remote_ts keep the tunnel scoped to known subnets instead of turning it into a default route for every packet. rekey_time shortens the lifetime of key material, while dpd_delay enables liveness checking so dead peers do not leave stale state behind. strongSwan’s configuration model exposes exactly those selectors, proposals, and peer-liveness controls, which map cleanly onto NIST’s guidance for tunnel mode, IKEv2, and periodic key refresh. Just as important, NIST’s broader network guidance warns that VPN-based access has limits in the current enterprise landscape. A secure tunnel does not solve segmentation, visibility, or granular authorization by itself. IDS and IPS Reveal Drift Firewalls and VPNs are excellent at enforcing expected paths, but they are not enough to detect misuse inside those paths. That is where network IDS and IPS become decisive. NIST’s IDPS guidance recommends products that combine signature-based detection, anomaly-based detection, and stateful protocol analysis because each method compensates for the others. Signature-based methods are efficient for known threats but weak against novel variants and evasion; anomaly-based methods can detect unknown abuse but are noisy without careful profiling; stateful protocol analysis helps distinguish legitimate protocol behavior from malformed or abusive sequences. NIST also stresses that these systems require tuning and that prevention actions should often be tested in simulation or learning modes before being enforced inline. A practical Suricata rule can be very small while still expressing a meaningful branch policy: Plain Text drop tls $HOME_NET any -> $EXTERNAL_NET any ( msg:"Deprecated TLS from branch host"; tls.version:1.0; sid:1001001; rev:1; ) The rule follows Suricata’s standard structure of action, header, and rule options. In IPS mode, drop blocks the flow and generates an alert, while tls.version:1.0 turns a broad “bad crypto” idea into an enforceable control that stops unsafe client negotiations at the branch edge. That kind of rule is useful because it binds transport hygiene to observable protocol behavior instead of relying on application owners to update every endpoint perfectly. The placement of the sensor still matters. NIST explicitly warns that network-based IDPS cannot inspect payloads inside encrypted traffic such as VPN, HTTPS, or SSH unless traffic is analyzed before encryption or after decryption. In a branch, that usually means placing inspection logically behind the VPN gateway for branch-to-core traffic and beside the egress path for direct internet breakout. Identity Turns Access into Policy The most important change in branch security is that authorization can no longer be inferred from attachment alone. NIST’s zero trust architecture states that access to enterprise resources should be granted on a per-session basis with least privilege, and that policy decisions can vary by identity, device status, network location, time, and other environmental signals. NIST’s secure network landscape guidance pushes the same idea further by arguing that user identity alone is not sufficient and that contextual information about devices and services must be part of the decision. CISA’s zero trust maturity model reinforces that direction by describing automated access controls that consider identity, device risk, application, and data category, and that are time-limited. At the branch edge, the most practical implementation is usually 802.1X with EAP-TLS backed by RADIUS. IEEE 802.1X defines mutual authentication for LAN-attached clients and ports, while EAP-TLS provides certificate-based mutual authentication and key derivation. Once that identity has been established, RADIUS can return standard attributes that place the endpoint into the correct VLAN and attach the correct ACL. RFC 3580 specifies the exact tunnel attributes used for VLAN assignment, and a FreeRADIUS users file can express the authorization response very compactly: Plain Text [email protected] Tunnel-Type := VLAN, Tunnel-Medium-Type := IEEE-802, Tunnel-Private-Group-Id := "120", Filter-Id := "finance-restricted" That snippet is intentionally small, but the effect is powerful. A successful 802.1X session for the named identity receives a VLAN and an access filter rather than broad branch connectivity. The same pattern can be extended from a named user to directory-driven roles, device classes, posture states, and time-bounded administrative sessions. It is also the reason identity-based access belongs in the network discussion rather than only in the IdP discussion: the branch switch or wireless edge becomes the first enforcement point where verified identity is translated into concrete packet-level reachability. Conclusion A secure branch is not created by stacking appliances and hoping that defense in depth emerges automatically. It is created by dividing responsibility cleanly across controls that complement one another. The firewall establishes a deny-by-default policy and limits what can traverse the site. The VPN protects selected traffic across untrusted transport without pretending that encryption is the same thing as trust. IDS and IPS expose misuse, drift, and protocol abuse that still occur inside permitted paths. Identity-based access ensures that branch attachment results in the minimum reachability justified by the authenticated subject and device, not by the convenience of a subnet. When those controls are composed deliberately, the branch stops being a soft edge and becomes a constrained, observable, and policy-driven part of the enterprise security fabric.

By Kamal chand Narra
Distributing Massive AI Models With Network-Layer Multicast
Distributing Massive AI Models With Network-Layer Multicast

When you are pushing terabytes of weights to hundreds of GPU nodes, unicast stops being a solution. Here is what actually works — and where multicast still struggles. The Problem Engineers Hit at Scale If you have ever watched a 70-billion-parameter model take 20 minutes to load across a 200-node inference cluster, you have felt this problem in practice. The culprit is almost always the same: the model server opens a separate TCP stream to each receiver, saturating its own NIC before the first node finishes loading. This is not a configuration issue. It is the fundamental geometry of unicast in a one-to-many scenario. For every additional receiver you add, the sender's bandwidth demand grows linearly. Distribute a 1 TB model to 100 nodes, and you are generating roughly 100 TB of traffic — all of it originating from the same host, all of it transiting the same top-of-rack switch. The math is simple: unicast sends N copies of your model. Multicast sends one copy and lets the network replicate it. For large clusters, the difference is orders of magnitude. Network-layer multicast solves this at the right abstraction level. Instead of the application managing individual connections, the network itself handles replication — copying packets only where distribution paths diverge. The sender transmits once; every receiver gets it. The practical upside: distribution time stops scaling with receiver count and becomes approximately constant. That said, multicast is not a drop-in replacement for your current distribution stack. The tradeoffs are real, and understanding them determines whether multicast belongs in your architecture. How Network Multicast Actually Works The mechanics are worth understanding before you evaluate whether to deploy this. When a node wants to receive multicast traffic, it joins a group address (e.g., 239.1.1.1 in the administratively scoped IPv4 range) by sending an IGMP membership report to its local router. The router records that interest and propagates it upstream. The network builds a distribution tree — typically using PIM-SM (Protocol Independent Multicast – Sparse Mode) or PIM-SSM (Source-Specific Multicast) for most data-center deployments. Packets enter the tree at the source and are replicated at each branch point as they flow toward receivers. No link carries duplicate traffic unless required by topology. The Distribution Workflow for Model Loading 1. Nodes scheduled to receive the model join a multicast group, typically identified by model version or checkpoint hash. 2. The model server segments the weights file into fixed-size chunks (commonly 64 KB–1 MB depending on MTU and FEC overhead) and begins transmitting to the group address. 3. Switches and routers replicate packets along the multicast tree. No receiver is privileged — all get the same stream simultaneously. 4. Each receiver tracks which chunks it has received, reassembles the model in shared memory, and loads it into accelerator memory once complete. 5. Missing chunks trigger repair requests. How those are handled is where implementation complexity lives. The result is synchronized parallel delivery. In a well-engineered deployment, you can go from "model server starts transmitting" to "all 200 nodes ready for inference" in roughly the same time it would take to deliver to one node over unicast. Unicast vs. Multicast: Side-by-Side Here is a direct comparison for a 1 TB model to 100 nodes: dimensionunicastnetwork multicast Traffic at sender N × model size 1 × model size Scales with receivers? Linearly worse Near-constant Congestion risk High (sender ToR) Distributed Reliability TCP guarantees Must be engineered Ops complexity Low Medium–High Best fit Small clusters, <20 nodes Large clusters, HPC, bootstrapping The bandwidth story is unambiguous. The reliability and operational story is where the real engineering work lives. The Reliability Problem (and How to Engineer Around It) Standard IP multicast runs over UDP. There is no acknowledgment, no retransmission, no ordering guarantee, and no congestion control. Drop a packet, and the network does not notice. For distributing cat videos, this is fine. For distributing model weights, it is not — a single missing chunk means every receiver that lost it cannot reconstruct the model. In practice, this is solvable, but it requires deliberate engineering. The approaches that work in production: 1. Application-Layer Reliability This is the most common approach for custom implementations. The sender assigns a sequence number to every chunk. Receivers track which sequences arrived. After a transmission window completes, receivers that missed chunks broadcast a NACK (Negative Acknowledgment). The sender retransmits missing chunks — typically via unicast to the specific requester to avoid generating duplicate traffic on the multicast tree. Practical tip: Use a NACK aggregation window (50–100 ms is a reasonable starting point) to avoid NACK implosion when many receivers miss the same chunk simultaneously. Collate NACKs server-side before deciding what to retransmit. 2. Forward Error Correction FEC (Raptor codes or Reed-Solomon are common choices) adds redundant encoded symbols to the stream. Receivers can reconstruct the original data from any sufficiently large subset of received symbols, even without a retransmission round-trip. This trades increased bandwidth (~5–10% overhead) for near-zero retransmission latency — useful when the network has predictable, bounded loss rates. Practical tip: FEC works best when loss is random and bounded. If you are seeing burst loss from switch buffer overruns, fix the congestion first — FEC will not save you from a sustained drop rate above its recovery threshold. 3. Hybrid Multicast/Unicast A pragmatic middle ground: use multicast for the initial bulk transfer (which has the highest bandwidth leverage) and fall back to unicast for repairs. Most receivers get 100% of chunks from the multicast stream. Stragglers use point-to-point retransmission to fill gaps. This avoids the complexity of pure reliable multicast while capturing most of the bandwidth benefit. 4. RDMA Multicast in HPC Fabrics If your cluster runs InfiniBand or RoCEv2, you have access to reliable RDMA multicast (UD multicast with software reliability layers, or IB reliable multicast extensions). This is not available in standard Ethernet fabrics but is worth noting for HPC and specialized AI hardware deployments. Why Most Hyperscalers Do Not Use Native IP Multicast This is the part that surprises engineers who arrive at this problem from a networking background. The bandwidth math is obviously favorable. So why are hyperscale AI clusters not running multicast everywhere? Three reasons, in order of practical impact: Control-plane complexity at scale. PIM state grows with the number of active groups and sources. In a dynamic AI cluster where job scheduling creates and tears down groups constantly, multicast routing state can become a significant operational burden. Debugging a stuck join or a flapping tree in a 10,000-node fabric is not straightforward.Application-layer alternatives are mature and integrated. NCCL (NVIDIA Collective Communications Library) provides AllReduce, Broadcast, and Scatter operations that are already optimized for GPU-to-GPU communication patterns. They integrate directly with PyTorch and JAX, handle topology awareness, and have years of production hardening. Building reliable multicast transport is an engineering investment that competes with "just use NCCL."Unicast TCP is boring in the best way. It has known failure modes, well-understood debugging tools, and works without fabric-level multicast support. For clusters below roughly 50–100 nodes, the bandwidth overhead of unicast is often acceptable. The honest framing: multicast is not universally better. It is specifically better for large-cluster, one-to-many distribution where bandwidth is the binding constraint and you are willing to invest in the reliability layer. Where Multicast Fits in the Current AI Infrastructure Landscape Given those tradeoffs, here are the deployment contexts where network multicast genuinely earns its complexity cost: Large Inference Farms When you are starting up hundreds of replicas of the same model simultaneously — a common pattern in autoscaling inference serving — multicast collapses what would be a serialized loading queue into a single parallel delivery. The bandwidth savings at this scale are substantial, and the operational overhead of managing multicast groups is manageable because the topology is relatively static. Checkpoint Synchronization in Distributed Training During training, periodic checkpointing saves model state to distributed storage and sometimes requires re-broadcasting the latest checkpoint to restore a failed worker. This is a clear one-to-many pattern where the checkpoint (potentially hundreds of gigabytes) needs to reach a set of known receivers simultaneously. Multicast is well-suited here. Private AI Clusters and HPC Environments If you control the fabric end-to-end — your own switches, your own routing, predictable topology — the operational complexity of multicast is much lower than in a multi-tenant cloud environment. This is where reliable multicast protocols have historically seen the most traction, and it remains the most viable deployment context today. Model Bootstrapping at the Edge Edge inference deployments (think CDN-scale or industrial IoT) often need to push model updates to large numbers of geographically dispersed nodes. Application-layer multicast over IP overlay networks (similar to BitTorrent-style distribution) is common here, though it trades network-layer efficiency for deployment simplicity. Practical Implementation Guidance If you are evaluating multicast for a specific use case, here is a concrete starting framework: Step 1: Validate Your Fabric Supports Multicast Before writing any application code, confirm that your switches support IGMP snooping (for confinement within VLANs) and that PIM is enabled on your router interfaces. In cloud environments, check whether your VPC supports multicast — many do not by default, and overlay solutions (GRE tunnels, VXLAN with multicast underlay) add latency and complexity. Shell # Quick sanity check on a Linux node ip maddr show # View joined multicast groups netstat -gn # Group memberships with interface tcpdump -i eth0 'ip[16] >= 224' # Capture multicast traffic Step 2: Design Group Namespace Multicast group address assignment matters for operational clarity. A practical scheme for AI workloads: Use SSM (232.0.0.0/8) rather than ASM to avoid Rendezvous Point complexityEncode model version or checkpoint ID into the group address or use a lookup tablePlan for group lifecycle — join on job start, leave on completion, and ensure IGMP leave messages propagate promptly Step 3: Build the Reliability Layer Explicitly Do not assume UDP reliability. At minimum, implement: Chunk sequencing with 64-bit sequence numbersPer-receiver bitmap tracking of received chunksNACK aggregation and retransmission (unicast repair is usually simpler)End-to-end checksum validation before model load Performance note: For a 1 TB model with 1 MB chunks, you have ~1 million sequence numbers to track per receiver. Use a sparse bitmap, not an array, or memory overhead becomes significant. Step 4: Test Failure Modes Deliberately The failure modes that will bite you in production are not random packet loss — they are: Late joiners: a node that joins mid-transfer needs either a full retransmit or a catch-up mechanismReceiver asymmetry: nodes with different NIC speeds or CPU load will have different loss profilesSwitch buffer overruns during the initial burst: implement sender-side rate limiting (start at ~70% of available bandwidth, tune up) What Is Coming Next The gap between multicast's theoretical efficiency and its practical deployment complexity is narrowing. A few developments worth tracking: Smart NIC and DPU offloads are pushing reliability processing off the host CPU, making application-layer reliable multicast cheaper to implement and operate. NVIDIA BlueField DPUs, for example, can handle NACK processing and chunk reassembly in dedicated network processing cores.SDN-orchestrated multicast trees — where a controller computes and installs multicast forwarding state based on real-time cluster topology — remove much of the per-hop PIM complexity and enable faster group setup/teardown in dynamic job-scheduling environments.Hardware vendors are adding native multicast acceleration to AI fabric switches. NVSwitch (in NVLink domains) has supported hardware multicast for GPU collective operations; similar capabilities are appearing in Ethernet-based AI fabrics.The IETF RIFT working group has active proposals around multicast-aware link-state routing for AI data centers, including MoE (Mixture-of-Experts) multicast use cases where different model experts are selectively distributed to different nodes. For exascale training runs and inference farms in the tens-of-thousands-of-nodes range, the bandwidth economics of multicast become increasingly hard to ignore. The infrastructure to support it reliably is maturing to match. Bottom Line for Practitioners Network-layer multicast is not a silver bullet, but it is the right tool for a specific problem: one-to-many distribution of large, identical payloads to clusters large enough that unicast bandwidth becomes the binding constraint. That problem is increasingly common as AI model sizes grow and inference clusters scale. The implementation cost is real — you need a reliability layer, fabric support, and operational tooling. For clusters under ~50 nodes or in environments where application-layer solutions like NCCL already cover your communication patterns, the tradeoff may not be worth it. For large-scale inference serving, checkpoint broadcasting, or HPC-style model distribution, it is worth the engineering investment. If your model loading time scales linearly with cluster size, multicast is the architectural lever that can make it near-constant. That is the question to ask before committing to either path. Further Reading Abdous et al., "One to Many: Closing the Bandwidth Gap in AI Datacenters with Scalable Multicast" — HotNets 2025NVIDIA NCCL Documentation — developer.nvidia.com/ncclIETF RIFT WG: LLM MoE Multicast use case — datatracker.ietf.org

By Vijayananda jayaraman
Best Practices for Handling Bad Data in Stream Processing Platforms
Best Practices for Handling Bad Data in Stream Processing Platforms

Today, stream processing platforms facilitate the real-time analysis of data flowing continuously from Internet of Things (IOT) devices, financial transactions, web applications and servers at banks, manufacturing equipment, logistical systems in warehouses and ships, as well as customer activities with conversational agents on web portals. Streaming frameworks like Apache Kafka, Apache Flink, Apache Spark Structured Streaming, and stream databases are empowering business folks to process millions of events in real time. But what your streaming platform is worth depends exclusively on the quality of data fed into it. An event that is malformed, a duplicate message, any missing field, or an invalid timestamp can lead to incorrect analytics generation, false alert triggers, bursts of alerts, and even application crashes. Batch processing allows for data to be cleaned before execution, but stream-processing requires that validation and corrections occur while the data is flowing. Thus, establishing a strong data quality strategy is a core necessity of any event-driven architecture. What Is Bad Data? Bad data refers to any event that fails to satisfy the quality rules required by downstream applications. Examples include: Missing mandatory fieldsInvalid data typesCorrupted JSON or Avro messagesDuplicate eventsIncorrect timestampsSchema incompatibilityOut-of-range sensor valuesFuture-dated eventsNull primary keysInvalid GPS coordinatesNegative financial valuesIncomplete business transactions Processing these events without validation can lead to unreliable business intelligence and poor operational decisions. Best Practices for Handling Bad Data 1. Validate Data at the Ingestion Layer The first validation should be right after data enters the platform. For event streaming data validation, validate data at the ingestion layer so that only high-quality, well-formed, and schema-compliant events reach our data lake. If we catch errors early in the pipeline, then the event flow passing through the rest of the stream processing components will be cleaner and more reliable, and it reduces the probability of processing invalid data later on. In simple words, rejecting invalid events early significantly reduces downstream complexity. 2. Enforce Schema Validation Enforce a schema to guarantee that every streaming event adheres to a data structure defined by us before it is operated on. It ensures data consistency, schema evolution with backward compatibility, and protects downstream consumers from non-well-formed or incompatible messages by validating field names, types, and required attributes against a schema. Along with a Schema Registry, it ensures producers and consumers agree on the event structure. 3. Detect Duplicate Events In a streaming platform, the ability to detect and eliminate duplicate events is critical — simply because our event could be sent multiple times due to retries, network outages, or producer errors. This includes avoiding duplicates and ensuring consistency across downstream systems that consume this data. And making sure there are no incorrect aggregations and duplicate transactions by creating reliable event processors. Processing duplicates could exaggerate revenue figures, inventory tallies, or analyses. 4. Validate Event Time One of the key features that modern stream processing should support is event-time processing. In streaming platforms, validating the event time is a key measure as it ensures that your events will be processed in the correct chronological order irrespective of whether they arrive late or out of sequence. Event timestamps are a prerequisite for accurate windowed aggregations to avoid duplicate or stale data affecting analytics (windowing needs distinct event timestamps), solidify data quality, and guarantee consistency in producing real-time insights and downstream processing. Using watermarks and event-time windows helps manage late-arriving events while preserving analytical accuracy. 5. Apply Business Validation Rules Technical validation makes sure that the ingested events have proper structures, completeness, and semantic validity – but it does not prove any business meaning. By applying business validation rules, we ensure that our events adhere to domain-level requirements (valid relationships, range of values, and business constraints) in order to keep dirty data from propagating downstream through systems and analytics. For example, some business rules like: Temperature between acceptable operating limits in temperature-measuring sensors.Customer ID exists, Product inventory is available, Order amount greater than zero in E-Commerce applicationsDevice status is active in IoT applicationsTransaction currency is supported in financial applications Business validation protects applications from logically incorrect data. 6. Route Bad Data to a Dead-Letter Queue (DLQ) If we are using Apache Kafka as a data/event ingestion tool for the stream processing platform, then the dead-letter queue (DLQ) of Kafka will play a very important role in segregating bad data or events from the flow of continuous data streams. Instead of processing bad data, we can route it to a dedicated DLQ. The following are the benefits: InvestigationRoot-cause analysisReprocessing the events after correction to minimize the maximum data lossProducer feedbackAudit trail A DLQ keeps production pipelines running while preserving problematic records for later analysis. 7. Separate Critical and Non-Critical Errors However, in stream processing, we should not react to every bad data with the same severity. Critical errors like invalid transactions, an empty key field, or a corrupted schema should be isolated or routed to a dead-letter queue (DLQ), so that they do not impact downstream processing. Non-critical errors, for example, a low-priority warning like a change in formatting or some kind of optional fields, can be logged, fixed, or handled with default values and positive acceptance of the stream processing. With the above approach, we can improve the production pipeline resilience. 8. Monitor Data Quality Continuously Data quality should be treated as an operational metric so that the following can be monitored to avoid bad data processing: Invalid event rateDuplicate percentageSchema failuresParsing failuresLate eventsDLQ growthProducer error rates Real-time dashboards from the above statistics would help engineering teams identify problems before they affect business users for decision-making. 9. Maintain Data Lineage To handle bad data in a stream processing platform, the first and essential step is to preserve data lineage. What does preserving data lineage mean? Put simply, it means recording the complete activity trajectory for every piece of data that flows through the platform. With it, one can trace the origin and circulation path of the data, as well as every modification it undergoes throughout the entire processing workflow, without missing any detail of changes related to the data. By recording the data's trajectory clearly, enterprises can quickly identify at which node the damaged, incomplete, or invalid data entered the data stream, and also calculate which downstream systems, or results generated relying on this data, will be affected. This avoids the situation where people only realize there is a problem long after the bad data has caused a large number of issues, and more importantly, it prevents them from being unable to pinpoint the source of the problem, only to fumble around with a pile of erroneous results. 10. Automate Data Quality Rules Avoid hardcoding validation logic inside application code whenever possible. Instead: Maintain reusable validation rules.Version business rules.Centralize governance.Allow configuration without code changes. Automation reduces maintenance effort and increases consistency across streaming applications. 11. Build Observability into the Pipeline Building observability into the pipeline is very important for detecting and handling bad data in stream processing platforms. Here are a couple of steps involved, such as continuously monitoring data quality, processing errors, latency, throughput, and unusual patterns in real time. With the help of metrics, logs, alerts, and dashboards, we can identify malformed, missing, or inconsistent data as soon as it occurs. Using the above, the teams can quickly investigate the source of the problem and subsequently take corrective action so that the entire pipeline can maintain reliable and accurate data for stream processing. Final Thoughts Building a stream processing platform is not only about high throughput or low latency. It is about having all decisions made based on accurate, trustworthy, and well-governed data. With ingestion-time data validation, schema enforcement, business rule application, duplicate detection, and late event handling mechanisms such as dead-letter queues (DLQs), steady monitoring for data quality issues, and designing for scale, builders can create a streaming architecture that withstands the test of time by providing you with the right insights in real time.

By Gautam Goswami DZone Core CORE
Why Do Some Proxies Work Fine for Search But Fail Once You Start Filtering Results?
Why Do Some Proxies Work Fine for Search But Fail Once You Start Filtering Results?

Automated web scraping, market intelligence data gathering, and large-scale search engine extraction platforms frequently hit an invisible wall. A collection of proxy IPs might execute initial search queries flawlessly, yielding a standard 200 OK status code and complete HTML payloads. However, the exact same backend application might immediately throw 403 Forbidden errors, encounter endless CAPTCHAs, or receive empty JSON responses the millisecond it applies structural filters — such as sorting by price, filtering by date range, or toggling deep category facets. To the application engineer, this behavior feels contradictory. If a network endpoint successfully authenticates, circumvents initial perimeter defenses, and extracts data from a root search page, why does a simple query parameter modifier trigger an immediate failure? Resolving this requires looking past simple HTTP status codes and examining how modern application security layers, distributed databases, and stateful networking layers interact. 1. Asymmetric Security Policies Across Application Layers Modern enterprise web architecture rarely relies on a single monolithic firewall. Instead, engineering teams route inbound traffic through multi-tiered infrastructure, consisting of an Edge Web Application Firewall (WAF), an API gateway, and individual backend microservices. Root search queries are frequently cached aggressively at the edge layer using Content Delivery Networks (CDNs). When a scraper requests the first page of a popular search term, the edge proxy handles the response immediately using cached static assets. Because the request never hits the primary database cluster, security infrastructure keeps the threat verification thresholds intentionally low to maximize throughput. Applying a strict data filter changes the operational footprint: Bypassing the cache engine: Custom parameter combinations (e.g., ?sort=price_asc&min_price=150&date=24h) create unique query strings that miss the CDN cache entirely.Dynamic query compilation: The request must penetrate directly to the core application code and database layer to compile a live dataset.Elevated security sensitivity: Because dynamic database execution consumes massive memory and CPU resources, backend security components apply significantly stricter rate-limiting thresholds and advanced behavioral analysis to filtered endpoints compared to public root URLs. 2. Advanced Fingerprinting and Stateful Behavioral Tracking When an automated script issues a baseline search request, it presents a set of connection attributes. Sophisticated security systems use this initial interaction to establish a baseline state, rather than blocking the IP instantly. Session and IP Footprint Inconsistencies If an application routes requests through standard datacenter proxies, the TCP/IP stack reveals distinct server signatures. Many modern anti-bot frameworks track the progression of a user journey. A legitimate human workflow naturally flows from a broad search query to localized filtering. If a client moves from a highly cached root query directly to resource-intensive processing pages within milliseconds, security engines cross-reference the client's network layer footprint. If the initial request used a rotating proxy line that abruptly shifts TCP sequence numbers, TLS session IDs, or cookies between the search phase and the filtering phase, the security perimeter flags the behavioral state machine as anomalous. High-Volume Query Traversal To extract filtered data systematically, automation loops often iterate through complex arrays of query parameters simultaneously: Python # A typical programmatic loop that exposes a weak proxy infrastructure categories = ["electronics", "apparel", "home"] pricing_structures = ["low", "medium", "high"] for category in categories: for price_tier in pricing_structures: execute_filtered_search(category, price_tier) When an application switches from general queries to rapid, concurrent execution of complex parameter strings, it sets off heuristic anomalies. If the underlying proxy network lacks deep pool diversity or advanced session sticky logic, the target's edge firewall aggregates the client's behavior across those parameters and drops the connections cleanly. To prevent these stateful anomalies from triggering blocks during complex data manipulation steps, network engineers utilize specialized architectures, which support granular switching between high-concurrency dynamic rotation for broad collection phases and static residential ISP connections to sustain long-duration, persistent sessions when deep structural filtering is required. 3. Parameter-Induced Payload Anomalies and TLS Profiling A query parameter change alters the raw HTTP payload string sent across the wire. This modification exposes the HTTP client or request library's default behavioral patterns to deep packet inspection engines. Query String Ordering and JA3 Fingerprints Many automated scrapers built on standard request frameworks (such as Python's requests or Node.js axios) pass query parameters as raw key-value dictionaries. Depending on how the underlying library serializes data into a string, the exact sequence of parameters may not match the explicit structure generated by modern browsers. Anti-bot systems combine this structural layout with a client's JA3 TLS fingerprint. A JA3 fingerprint hashes specific parameters found within the Client Hello packet during the cryptographic handshake, including: TLS versionAcceptable cipher suitesExtension listsElliptic curvesElliptic curve formats If a client sends a standard root search query, a mismatching JA3 profile might only trigger a soft warning score. But when that same client requests a highly specific data filter — a behavioral pattern that consumes higher resource costs — the security system evaluates the warning score against a much tighter tolerance threshold, dropping the connection immediately. 4. Cryptographic Validation and Forced Client Challenges When a user targets deep structural filter routes, advanced application firewalls often issue silent cryptographic challenges, such as Proof-of-Work (PoW) scripts or dynamic JavaScript injection, to verify client authenticity before executing database queries. A basic proxy setup merely passes raw text and network packets back and forth. It has no way to evaluate or solve a JavaScript execution request natively. If your automated pipeline uses a simple HTTP client rather than a fully coordinated headless browser configuration (like Playwright or Puppeteer) capable of solving these dynamic challenges on the fly, the request fails precisely at the filtering step. The root page works because it did not require a challenge, while the complex filter endpoint demands explicit client execution verification. Mitigating Filtering Failures: Engineering Checklists To build resilient data collection pipelines capable of executing complex filtering workflows without triggering continuous network rejections, development teams should implement the following structural optimizations: Decouple the network stack from the automation logic: Ensure your infrastructure abstracts request coordination, allowing headers, cookies, and TLS handshakes to remain completely uniform while parameters rotate.Implement structural header sanitization: Ensure HTTP headers (such as User-Agent, Accept-Language, Sec-Ch-Ua, and Authorization) maintain strict chronological and case-sensitive order across all downstream filtering pipelines.Normalize parameter serialization: Match the exact parameter encoding and serialization sequence used by real browsers. Avoid random dictionary serialization; instead, construct query parameters explicitly using deterministic arrays or ordered maps.Enforce intelligent session persistence: For deep filtering journeys, leverage sticky session proxy lines to maintain a single, unbroken TCP connection and TLS context throughout the entire user funnel, switching back to dynamic rotation only when initiating entirely new search scopes.

By xiyun chen
Architecting Autonomous Network Ecosystems: From Reactive Monitoring to Agentic AI Orchestration
Architecting Autonomous Network Ecosystems: From Reactive Monitoring to Agentic AI Orchestration

Agentic AI systems represent a paradigm shift in network operations, facilitating the transition from traditional reactive monitoring to fully autonomous management frameworks. For global infrastructure leaders, these specialized AI agents serve as persistent digital engineers, providing round-the-clock expertise across deployment, maintenance, and complex troubleshooting lifecycles. The following blueprint delineates the strategic application of agentic AI within a global enterprise network operations environment. Architectural Blueprint: Multi-Agent Network Engine Rather than deploying a monolithic AI entity, the optimal architecture utilizes a multi-agent system (MAS). In this model, specialized agents collaborate through a centralized Orchestrator to achieve complex operational objectives. Please refer to the System Hierarchy and Flow, as well as the Strategic Vision and Ecosystem diagrams. System Hierarchy and Flow Strategic Vision and Ecosystem Core Use Cases and Agent Workflows Autonomous Provisioning and Zero-Touch Deployment Functional scope: Serves as an automated configuration and systems engineer.Workflow: Human inputs a high-level intent (e.g., "Provision a new Cisco core switch for the Seoul R&D campus").Design Agent reads existing topology diagrams and ipAM (IP Address Management) databases.Configuration Agent generates vendor-specific CLI configs (Cisco IOS/NX-OS).Validation Agent runs the config in a virtual sandbox (e.g., Cisco Modeling Labs) to check for routing loops before pushing to production via Ansible. 24/7 Autonomous Incident Triage and Resolution Functional scope: Functions as the primary intelligence layer for Network Operations Center (NOC) alerts.Workflow: A monitoring tool (e.g., Splunk, SolarWinds) triggers a "BGP neighbor down" alert.Triage Agent intercepts the alert and instantly queries the device via SSH or telemetry API.Diagnostic Agent executes diagnostic scripts (show ip bgp summary, traceroute), analyzes logs, and identifies the root cause (e.g., a flapping fiber link).Resolution Agent opens a Jira ticket, attaches all logs, attempts a safe automated fix (like shifting traffic to a backup path), and pages a human only if the physical hardware needs replacement. Predictive Maintenance and Capacity Optimization Functional scope: Operates as a proactive infrastructure strategist and planner.Workflow: Analysis Agent continuously monitors interface bandwidth, memory usage, and optical transceivers' error rates across global data centers.Forecasting Agent identifies trends (e.g., "Link X between Vietnam and Korea factories will hit 95% capacity in 30 days during peak hours").Planning Agent drafts a change management proposal recommending a bandwidth upgrade or traffic re-routing plan for human review. Automated Compliance and Security Patching Functional scope: Functions as a continuous vulnerability and configuration compliance auditor.Workflow: Cisco releases a critical security advisory for an OS vulnerability.Auditor Agent scans the entire inventory database to find all vulnerable device models.Patching Agent schedules a maintenance window, backs up current configurations, downloads the verified firmware, applies the patch sequentially to avoid downtime, and performs post-flight checks. Implementation Strategy To ensure organizational stability while maximizing technological advancement, a phased implementation strategy is recommended: Phase 1: Read-Only Agents (Information Gathering) Allow agents to access logs, APIs, and read-only commands.Focus on automated documentation, ticket enrichment, and summarizing alerts. Phase 2: Human-in-the-Loop (Co-Pilot) Allow agents to generate fixes and configuration scripts.Require a senior network engineer to review and click "Approve" before any execution. Phase 3: Guardrailed Autonomy (Full Agentic) Give agents autonomous execution rights only for low-risk, repetitive tasks (e.g., port resets, clearing stuck sessions).Enforce hard boundaries using API rate limits and strict verification checklists. To refine the architectural requirements for your specific environment, please provide insights on the following: What monitoring tools (e.g., Datadog, ServiceNow) and automation frameworks (e.g., Ansible, Terraform) does your team currently use?What is the most repetitive issue your 24/7 NOC team spends time fixing manually?Are you looking to build these agents using commercial LLM APIs or host open-source models locally for security reasons? Building an Enterprise-Grade Agentic System Constructing an enterprise-grade agentic system for high-security environments requires the integration of a frontier large language model (LLM), a robust production agent framework, and the Model Context Protocol (MCP) to establish secure interoperability with core network infrastructure. Part 1: Choosing the Right Tool/Solution Do not rely on a simple chatbot web interface. You need an API-driven architecture that combines a foundational model with an agent framework. The Foundational Model (The Brain) Top Choice: Anthropic Claude 3.5 Sonnet / Claude 3 Opus Why: It currently dominates tool-use (function calling), reasons through complex, multi-step engineering logic flawlessly, and natively supports MCP. On-Premises / Air-Gapped Alternative: Llama 3.1 / 3.3 (70B or 405B) or Qwen 2.5 (72B) Why: For internal Samsung networks with strict data privacy laws, you can host these open-source models locally using vLLM or Ollama. They have excellent coding and structured JSON output capabilities. The Agent Framework (The Backbone) Use an open-source framework to manage agent memory, states, and collaboration: LangGraph (by LangChain): Best for networking. It allows you to build cyclical, graph-based agent workflows with strict state control and mandatory human-in-the-loop approval stages.CrewAI: Great for quickly setting up role-based multi-agent teams (e.g., Triage Agent talking to a Scripting Agent). Part 2: Understanding MCP (Model Context Protocol) MCP is an open standard created by Anthropic that acts as a secure plug-and-play adapter between LLMs and local/remote data sources, tools, and systems. Instead of writing custom API integration code for every single Cisco switch, Ansible Tower, or Jira server, you build or use an MCP Server. How it works: Your Agent (MCP Client) connects to an MCP Server. The MCP Server exposes specific tools (e.g., run_cisco_command, query_monitoring_alerts) to the agent dynamically. Security Benefit: The model never gets direct SSH access to your core switches. The model only talks to the MCP Server, which enforces strict argument validation, sanitization, and logging before executing anything on the network. Part 3: Writing agents.md The agents.md file defines the architecture, roles, personas, boundaries, and collaboration patterns of your AI team. Markdown # Network Operations Multi-Agent Architecture This document defines the specialized AI agents operating within the Network Operations Center (NOC). ## 1. System Orchestrator Agent - **Role:** Central Dispatch & Intent Router - **Goal:** Analyze incoming alerts or human engineer requests and delegate tasks to specialized agents. - **Persona:** A highly organized, senior technical project manager. - **Boundaries:** Does not execute network commands directly. Must always route tasks and compile final reports. ## 2. Network Diagnostics Agent (NetDiag-Agent) - **Role:** Incident Triager and Log Analyst - **Goal:** Investigate network anomalies, verify device status, and pinpoint root causes. - **Persona:** An analytical Cisco CCIE-certified troubleshooting expert. - **Tools Allowed:** `ssh_read_only_commands`, `query_splunk_logs`, `ping_traceroute`. - **Boundaries:** Read-only access to infrastructure. Cannot modify configurations. ## 3. Network Automation Agent (NetAuto-Agent) - **Role:** Configuration and Deployment Engineer - **Goal:** Generate valid, syntax-correct network configurations and execute approved automation scripts. - **Persona:** A precise Network Automation Engineer specializing in Ansible, Python (Netmiko/Nornir), and Cisco IOS/NX-OS. - **Tools Allowed:** `generate_ansible_playbook`, `validate_config_syntax`, `execute_stage_change`. - **Boundaries:** Write-access allowed *only* through staging/sandbox tools. Any production push requires an explicit `Human-In-The-Loop` (HITL) approval token. Part 4: Writing skills.md The skills.md file maps out the actual capabilities, API tools, and Python execution blocks that the agents can tap into via MCP. Markdown # Network Agent Skills & Tool Definitions This document details the functional tools exposed to agents via the MCP (Model Context Protocol) layer. ## Category: Network Telemetry & Read Skills ### `query_device_status` - **Description:** Fetches real-time operational data from a specific network device using Netmiko or Cisco DNA Center API. - **Arguments:** - `device_ip` (string, required): The target management IP address. - `command` (string, required): Allowed values: `show ip interface brief`, `show ip bgp summary`, `show environment`. - **Safety:** Input string regex validation enforced to prevent CLI injection attacks. ### `fetch_noc_alerts` - **Description:** Pulls active high-severity network alerts from Splunk/SolarWinds. - **Arguments:** - `severity` (string): Defaults to "CRITICAL". - `lookback_minutes` (integer): Time window to check. ## Category: Network Modification Skills (Write) ### `deploy_ansible_playbook` - **Description:** Triggers an Ansible AWX template to push configuration updates to a device group. - **Arguments:** - `template_id` (string, required): Pre-defined template ID in Ansible. - `extra_vars` (json, required): Key-value pairs for variables (e.g., target VLAN, interface ID). - **Security Policy:** **CRITICAL_APPROVAL_REQUIRED**. This skill automatically pauses agent execution and sends a webhook to the human supervisor's teams/Slack app for a 2FA confirmation click. Next Steps for Implementation To help map out a proof of concept (PoC) for your architecture, tell me: Do your network infrastructure components support REST APIs/gRPC, or do the agents need to interface heavily via legacy SSH/CLI parsing?Do you plan to build this as an internal web-dashboard/chatbot for engineers, or as a background event-driven system triggered by network monitoring systems?What programming language (e.g., Python, TypeScript) is your team's preference for building the MCP servers? Check out more from my series here.

By Daniel Oh DZone Core CORE
From Polling to PubSub: Building an Asynchronous OPC UA Stack in Python
From Polling to PubSub: Building an Asynchronous OPC UA Stack in Python

Industrial control systems are generating more data than ever before, but the Python tooling used to process this telemetry often encounters severe performance constraints. Traditional OPC UA libraries are built around synchronous, polling-based Client and Server architectures. When industrial networks scale to thousands of sensors broadcasting high-frequency data, these synchronous Python implementations choke. To handle this modern many-to-many topology, developers need a native Publisher and Subscriber solution that does not block the execution thread while waiting for network packets. For Python developers unfamiliar with industrial protocols, OPC UA PubSub (IEC 62541-14) is a standard that decouples data producers from consumers by allowing devices to broadcast telemetry via stateless middleware like UDP Multicast. For industrial engineers new to Python concurrency, asyncio is a standard library that uses an event loop to handle thousands of simultaneous network operations concurrently without the heavy overhead of traditional threading. Bridging these two paradigms requires a completely non-blocking architecture. To address this gap, a complete asyncio driven OPC UA PubSub implementation was architected and integrated into the open source opcua-asyncio library (merged in Commit 2b6f3e5). Implementing this standard from scratch in an asynchronous Python environment presented unique challenges. This article breaks down the engineering decisions and technical design patterns used to build this extension. By contributing this capability to a library that serves thousands of developers in the Python IIoT ecosystem, the goal is to ensure engineers can now build highly scalable publisher and subscriber sensor networks without migrating away from Python. The Shift to Publisher and Subscriber in IIoT In traditional OPC UA, a client polls a server or sets up monitored items. This creates a tightly coupled, connection-oriented topology. The PubSub extension decouples this by allowing publishers to broadcast telemetry data via stateless middleware like UDP Multicast or MQTT, which subscribers can passively ingest. To bring this to the opcua-asyncio ecosystem, the architecture needed to bridge the gap between Python's asynchronous event loop and the highly deterministic, byte-packed UADP (OPC UA Datagram Protocol) structures. The design was broken down into four core pillars. Asynchronous transport layer: Managing non-blocking UDP and IP multicast.UADP binary protocol engine: Bit-level packing and unpacking of network messages.Data abstraction and node mapping: Linking arbitrary network payloads to the OPC UA Address Space.Concurrency and connection management: Orchestrating readers, writers, and tasks via asyncio. Pillar 1: The Asynchronous UDP Transport Layer OPC UA UADP relies on UDP for low-latency transmission. In Python, synchronous socket operations block the main thread, which is fatal to an asyncio application. To solve this, the networking layer was built directly on top of asyncio.DatagramProtocol. The OpcUdp class overrides the standard protocol callbacks to bridge the network socket with the PubSub receiver logic. Here is a look at how the protocol was extended and hooked into the event loop to ensure incoming datagrams never block the main thread. Python class OpcUdp(asyncio.DatagramProtocol): def __init__(self, cfg: UdpSettings, receiver: Optional[PubSubReceiver], publisher_id: Variant) -> None: super().__init__() self.cfg = cfg self.receiver = receiver self.publisher_id = publisher_id.Value def datagram_received(self, data: bytes, source: Tuple[str, int]) -> None: try: buffer = Buffer(data) msg = UadpNetworkMessage.from_binary(buffer) if self.receiver is not None: asyncio.ensure_future(self.receiver.got_uadp(msg)) except Exception: logging.exception("Received Invalid UadpPacket") Socket lifecycle: The UdpSettings class manages socket creation by carefully applying SO_REUSEADDR and handling both IPv4 (AF_INET) and IPv6 (AF_INET6) multicasting.Multicast configuration: Depending on the IP family, IP_ADD_MEMBERSHIP or IPV6_JOIN_GROUP are injected directly into the socket options via the struct module to ensure the application correctly subscribes to IGMP or MLD groups.Non-blocking reception: When a datagram hits the interface, datagram_received immediately passes the raw bytes to the UADP decoding engine and dispatches the resulting parsed message to a background task using asyncio.ensure_future(). This guarantees the networking thread is instantly freed to handle the next packet. Pillar 2: The UADP Binary Protocol Engine The UADP specification defines an extremely dense, highly variable network packet. Headers can dynamically expand or contract based on a series of bit flags. Processing this in Python requires rigorous byte manipulation to maintain both memory efficiency and processing speed. The uadp.py implementation utilizes Python's enum.IntFlag to map the exact bitwise schemas defined in OPC UA Part 14. Python class MessageHeaderFlags(IntFlag): NONE = 0 UADP_VERSION_BIT0 = 0b1 PUBLISHER_ID = 0b00010000 GROUP_HEADER = 0b00100000 PAYLOAD_HEADER = 0b01000000 EXTENDED_FLAGS_1 = 0b10000000 # FlagsExtend1 PUBLISHER_ID_UINT16 = 0b0000000100000000 PUBLISHER_ID_UINT32 = 0b0000001000000000 PUBLISHER_ID_UINT64 = 0b0000011000000000 PUBLISHER_ID_STRING = 0b0000010000000000 Flag-driven serialization: The UadpHeader and UadpDataSetMessageHeader are deeply nested and conditional. For example, the Extended Flags dictate whether a PublisherId is encoded as a Byte, UInt16, UInt32, UInt64, or String.Bitwise extensibility: The implementation cascades flags using EXTENDED_FLAGS_1 and EXTENDED_FLAGS_2 bits. If the integer value of the required flags exceeds 0xFF, the engine dynamically shifts the bytes and appends the extension flags.Binary packing: A standardized Primitives unpacking utility translates the raw buffer directly into strictly typed Python objects like UInt32, Guid, or DateTime. This avoids the overhead of intermediate object instantiation when parsing high-frequency sensor data.Delta Frames vs. raw data: The parser dynamically routes payload deserialization based on MessageDataSetFlags. It distinguishes between Key Frames, Delta Frames, and Raw Data while packing the resulting generic DataValue structs into a unified UadpNetworkMessage. Pillar 3: Data Abstraction and Address Space Integration Receiving data is only half the battle because that data must meaningfully map to the server's Address Space. The architecture introduces PubSubInformationModel to handle this synchronization. Datasets and metadata: A PublishedDataSet defines the structure of the data being transmitted. This includes tracking FieldMetaData, built in types, and value ranks.Dynamic variable substitution: The PubSubDataSourceServer class abstracts the retrieval of data from the server tree. It safely reads attributes and falls back to a SubstituteValue if a node status code is bad. This ensures unbroken telemetric streams.Subscribed mirrors: When an OPC UA client acts as a subscriber, it needs to see the incoming data reflected in its own node tree. The SubscribedDataSetMirror dynamically creates new variable nodes on the fly to match the incoming DataSetMetaData. This dynamic node mapping was engineered by injecting new variables straight into the server tree based on the metadata specification. Python async def _create_and_set_node(self, f: FieldMetaData): if self._node is None: raise RuntimeError("SubscribedDataSetMirror._node is not initialized.") n = await self._node.add_variable( NodeId(NamespaceIndex=Int16(1)), "1:" + str(f.Name), Variant(), datatype=f.DataType ) await n.write_attribute(AttributeIds.Description, f.Description) await n.write_attribute(AttributeIds.ValueRank, f.ValueRank) await n.write_attribute(AttributeIds.ArrayDimensions, f.ArrayDimensions) return n Target variables: Alternatively, SubScribedTargetVariables maps incoming dataset fields directly to existing NodeId references in the server. These references update in real time as UDP packets are decoded. Pillar 4: Concurrency and Connection Management The top-level orchestration is handled by the PubSubConnection and PubSub classes. These act as the asynchronous lifecycle managers. Task gathering: When start() is invoked on a connection, the lifecycle manager utilizes asyncio.gather() to concurrently spin up all associated DataSetReader and DataSetWriter tasks without blocking the main OPC UA server loop. Python async def start(self) -> None: logging.info("Starting Connection %s", await self.get_name()) loop = asyncio.get_event_loop() sock, _, _ = self._network_settings.create_socket() self._transport, self._protocol = await loop.create_datagram_endpoint( lambda: self._network_factory(self._network_settings, self._receiver, self._cfg.PublisherId), sock=sock, ) self._writer_tasks = asyncio.gather(*[writer.run(self._protocol, self._app) for writer in self._writer_groups]) reader_tasks = asyncio.gather(*[reader.start() for reader in self._reader_groups]) await reader_tasks if self._protocol is not None: self._protocol.set_receiver(self._receiver) await self._set_state(PubSubState.Operational) Protocol decoupling: To prevent circular dependencies between the network transport and the information model, strict interfaces defined in protocols.py are used. The UDP protocol layer communicates with the logical layer strictly through these abstract protocols.Wildcard routing and readers: The ReaderGroup acts as an intelligent multiplexer. When a multi-payload UADP packet arrives, it analyzes the GroupHeader and DataSetPayloadHeader. It then routes individual DataSetMessages to the correct DataSetReader instances by matching wildcard filters.Timeouts and state machines: Robust industrial systems must handle connection drops. The DataSetReader wraps its operation in a dedicated timeout task. Using asyncio.wait_for(), it actively monitors for MessageReceiveTimeout events. If a heartbeat or payload is missed, it transitions the internal PubSubState to Error. This allows higher-level application logic to gracefully degrade. Conclusion Building a production-ready OPC UA PubSub stack in Python requires harmonizing the stringent bit-packed demands of the IEC 62541-14 specification with the asynchronous paradigms of asyncio. By leveraging asyncio.DatagramProtocol for deterministic networking, abstracting the UADP bit flags into structured classes, and deeply integrating with the OPC UA Address space via mirrored target variables, this implementation provides a scalable foundation for modern IIoT architectures. Code and Open Source Contributions The architecture and implementation details discussed in this article were merged into the core FreeOpcUa/opcua-asyncio repository. You can explore the complete implementation, including the raw protocol parsing and asyncio abstractions, via the links below. Primary commit: 2b6f3e5 (Initial implementation of OPC UA PubSub UDP and UADP). Key files to explore in the commit: asyncua/pubsub/udp.py: Contains the OpcUdp transport layer and multicast socket configuration.asyncua/pubsub/uadp.py: Houses the flag driven serialization and binary protocol engine.asyncua/pubsub/connection.py: Demonstrates the asyncio task management and lifecycle orchestration.

By Harshith Narasimhan Srivatsa
Solving Data Traffic Jams in Your Network
Solving Data Traffic Jams in Your Network

Stop, start. Stop, start. Nothing brings data flows to a grinding halt (or raises an admin’s blood pressure) quite like network congestion. The unwanted, unexpected extra step in an information request or response operation chain is a telltale sign that something’s changed or isn’t working in your infrastructure. And heavier traffic is more than just an inconvenience – it’s a multifaceted problem with knock-on business effects that falls upon admins to identify and fix. Let’s dig deeper into network traffic jams, their primary causes, and how to resolve and prevent them. Understanding What Causes a Digital Traffic Jam Network congestion occurs when the demand for sending or receiving data exceeds the network’s capacity. In other words, a computer network link can’t handle the volume of data trying to use it. It’s like what happens when a person tries to pour more water through a straw than it can handle at once. At a certain point, there’s simply not enough space, causing a backup in the straw. In computer networks, when data packets exceed the network’s capacity, they’re similarly queued in network devices, leading to increased latency and, in turn, traffic jams. 7 Most Common Causes of Network Congestion Bandwidth bottlenecks: When the capacity of network links (such as cables or wireless connections) is insufficient to handle the amount of data being sent.Network device limitations: Routers, switches, and other devices have limited processing power and memory and can become overwhelmed when handling large volumes of traffic.Broadcast storms: A situation where a network becomes flooded with broadcast or multicast packets, often caused by misconfigured devices or faulty hardware.High-bandwidth applications: Applications that consume a lot of network resources, such as video streaming, large file transfers, and backup operations.DDoS attacks: A distributed denial-of-service (DDoS) attack occurs when a network is intentionally flooded with excessive traffic from multiple sources.Poor network architecture: Inefficient routing or inadequate network capacity planning can lead to congestion hotspots.Insufficient internet speeds: Slow service-provider connections can cause bottlenecks at the edge of the network. Performance and Business Consequences of Network Congestion The consequences of network congestion extend far beyond the digital realm, wreaking havoc on your entire IT infrastructure. As data packets get caught in the congestion chaos, you’ll see increased latency and sluggish application performance. Network devices, overwhelmed by traffic, might then start dropping packets, causing retransmissions that add more load and exacerbate congestion. Worse, applications can start to time out because they can’t handle the lengthy delays in data transmission, further compounding the problem. You're also likely to notice jitter, or uneven packet delays, that affect real-time applications like VoIP and video conferencing. Network throughput suffers too, with the overall amount of data that can be transmitted over the network taking a nosedive. Ultimately, users soon begin to notice this digital snarl-up, with slow network performance leading to a decline in productivity and potentially a negative impact on your bottom line. Quality of Service (QoS) for critical applications can degrade as they struggle to receive the priority they need amid congestion. The overarching message is that network congestion can have serious repercussions on performance, end-user experience, and business operations as a whole. Maintaining healthy network traffic is about speed, sure, but it’s also about supporting day-to-day operations. 10 Proven Solutions for Fixing Bad Network Traffic This doesn’t need to be the network status quo. Here’s how admins can and should take back control: Bandwidth management and QoS: Implement QoS policies to prioritize important traffic, effectively creating an express lane for your VIP data packets. Use traffic shaping to control data flow and prevent one application from hogging all the bandwidth.Network segmentation: Divide your network into smaller subnets to contain congestion and prevent a problem in one area from spreading like wildfire.Upgrade network infrastructure: Sometimes you just need more oomph. Upgrade your network devices, increase link capacities, and consider SDN for greater flexibility in traffic management. Optimize application performance: Collaborate with your development teams to improve network efficiency via data compression and caching.Implement caching and Content Delivery Networks (CDNs): For frequently accessed data or web content, use caching or CDNs to lighten the load on your primary network and improve data transfer speeds.Regular network performance monitoring and analysis: Keep a watchful eye on your network performance to identify congestion points and proactively address network issues before they spiral out of control.Load balancing: Distribute network traffic across multiple paths or servers to prevent any single point from becoming a bottleneck.Traffic prioritization: Prioritize critical unicast and multicast traffic over less important data flows.Optimize routing: Regularly review and optimize routing protocols and configurations to ensure efficient traffic flow.Firewall optimization: Ensure your firewalls are properly configured and can handle the traffic load; poorly configured or underpowered firewalls can become network bottlenecks. Keeping Data Speeds Up and Bottom Line Impacts at Bay Again, this is more than about speed (or lack thereof), but the impact of bad network traffic and how it can become a serious business problem. The good news is that it doesn’t have to be a digital death sentence for your IT infrastructure. With a combination of smart network management strategies and the right monitoring tools, you can effectively tackle network congestion and keep your network in the fast lane.

By Sascha Neumeier
Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot
Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot

Managing high-volume message traffic in distributed architectures is crucial. Efficient use of database and CPU resources is also very important. There are structures that allow us to receive messages in batches. The default Spring Kafka "BatchMessageListener" structure addresses this need. However, the processing of these messages often goes through a sequential bottleneck. This article will discuss the structure and usage of Kotlin Coroutines in detail. We will examine how to maximize Kafka message processing performance using Structured Concurrency principles and Resource Throttling techniques. Architectural Bottleneck: Sequential I/O Blocking On the current Kafka listener: Database or external service calls made for each message directly increase total processing times. If the processing speed of a message lags behind the message arrival speed and the max-poll-interval-ms time is exceeded, the consumer is removed from the consumer group. Rebalancing is triggered, and the partitions of that consumer are redistributed to other consumers in the group. Kotlin @KafkaListener(topics = ["usage-pool-topic"]) fun usagePoolListener(records: List<ConsumerRecord<String, String>>) { records.forEach { record -> processRecord(record) // Network latency + DB I/O blocking } } Solution 1. Batch-Fetch and In-Memory Map Structure Before any concurrent code is entered, data is retrieved collectively from all necessary entities. Multiple separate queries are converted into a batch query before data processing begins. The N+1 query problem is solved at the application layer. All data is cached once before being broken down into concurrent operations. Having the data cached significantly reduces our reliance on the database. Using the associateBy function, we transform the data into a map structure with X access times. This allows us to read the data safely from the maps instead of reading each concurrent operation from the database. Kotlin val messages = records.map { objectMapper.readValue(it.value(), UsagePoolRecord::class.java) } val usagePoolEntities = usagePoolRepository .findByIds(messages.map { it.usagePoolId.toBigInteger() }) .associateBy { it.usagePoolId } val lockEntities = lockRepository .findByUserIds(messages.map { it.userId }) .associateBy { it.userId } 2. Structured Concurrency Memory Management With Chunking The chunk structure serves two purposes. It prevents the creation of coroutines simultaneously. This prevents unnecessary memory usage. Each chunk writes to the database after all coroutines have completed their operations. Unnecessary connection pool consumption is avoided. Kotlin messages.chunked(150).forEach { chunk -> // Each chunk of 150 records is processed concurrently } Resource Isolation With limitedParallelism Why limitedParallelism? If the database connection pool has, for example, X connections, keeping the parallelism limit below X prevents "Connection Timeout" errors. Kotlin messages.chunked(150).forEach { chunk -> val deferredResults = chunk.map { record -> CoroutineScope(Dispatchers.IO.limitedParallelism(15)).async { try { processRecord(record, usagePoolEntities, lockEntities) } catch (e: Exception) { log.error("Operation error: ${record.key()}", e) buildErrorRecord(record, e) } } } val results = deferredResults.awaitAll() // Structural waiting collectAndAggregate(results) } The Dispatchers.IO.limitedParallelism(X) command limits the number of concurrent coroutines to X, preventing the DB connection pool from being exhausted.Each coroutine returns a result with the async command. The awaitAll() command waits for all coroutines in the chunk to finish before proceeding to the next step. runBlocking This function blocks callers until all concurrent operations are complete. This is the correct approach here because: It ensures that the Kafka consumer remains blocked to maintain its offset commit structure until all records in the batch are processed. We still benefit from concurrent operation parallelism within the runBlocking block. 3. Thread-Safe Result Structure After the awaitAll() operation, all results are collected in thread-safe queues. Then a single batch write operation takes place. Using MutableList structures to combine results returned from parallel processed coroutines can lead to data loss. At this point, lock-free data structures should be preferred. ConcurrentLinkedQueue uses CAS (Compare-And-Swap) algorithms instead of synchronized blocks. This provides superior performance in high-content write operations. Why Shouldn't We Use ConcurrentLinkedQueue? Concurrent operations (concurrent functions) perform simultaneous write operations to a shared collection of results. Using MutableList leads to race conditions. It performs well in secure and concurrent write operations. Kotlin data class AggregatedRecords( val processedSave: ConcurrentLinkedQueue<ProcessedEntity> = ConcurrentLinkedQueue(), val toDelete: ConcurrentLinkedQueue<UsagePoolEntity> = ConcurrentLinkedQueue(), val retryQueue: ConcurrentLinkedQueue<RetryEntity> = ConcurrentLinkedQueue() ) The DataIntegrityViolationException return is important. When two consumer instances are processing the same record, one of them falls into a unique constraint violation. Instead of making the entire batch fail, record-by-record deletion is performed. Kotlin AggregatedRecords.processedSave .chunked(150) .forEach { batch -> try { processedRepository.saveAll(batch) } catch (e: DataIntegrityViolationException) { batch.forEach { record -> try { processedRepository.save(record) } catch (e: DataIntegrityViolationException) {} } } } 4. Error Tolerance in Write Operations Batch write (saveAll) operations are performant. However, a "Unique Constraint" error in a single record can cause the entire batch to fail. The following structure is critical to meet Optimistic Locking or Idempotency requirements. Kotlin aggregatedRecords.processedSave.chunked(150).forEach { batch -> try { processedRepository.saveAll(batch) } catch (e: DataIntegrityViolationException) { // Fallback: Try one by one if batch fails batch.forEach { record -> try { processedRepository.save(record) } catch (innerException: DataIntegrityViolationException) { log.warn("Duplicate record skipped: ${record.id}") } } } } 5. Data Flow Diagram Ingress: The Kafka batch is caught with runBlocking.Preparation: All necessary context data is retrieved bulk from the DB.Execution: Coroutines are started asynchronously in chunks.Synchronization: The completion of all coroutines is awaited as a barrier point with awaitAll().Egress: Collected results are made permanent with saveAll. Performance Analysis and Results Conclusion Processing Kafka messages in Spring Boot with Kotlin Coroutines not only increases speed but also improves code readability and makes resource management deterministic (predictable). The use of runBlocking allows us to build a bridge between the blocking Kafka consumer thread and the suspended world without disrupting Kafka's offset management mechanism. Dependencies XML <dependency> <groupId>org.jetbrains.kotlinx</groupId> <artifactId>kotlinx-coroutines-core</artifactId> <version>1.7.3</version> </dependency> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency>

By Erkin Karanlık

Monthly Top IoT Experts

expert thumbnail

Tim Spann

Senior Sales Engineer,
Snowflake

Tim Spann is a Senior Sales Engineer. He works with Python, SQL, Snowflake, Cortex AI, Apache Iceberg, ML, Notebooks, Jupyter Notebooks, Generative AI, LLM, Vectors, Apache NiFi, Apache Pulsar, Apache Kafka, Apache Flink, Flink SQL, Apache Pinot, Trino, Apache Iceberg, DeltaLake, Apache Spark, Big Data, IoT, Cloud, AI/DL, machine learning, and deep learning. Tim has over a ten years of experience with the IoT, big data, distributed computing, messaging, streaming technologies, and Java programming. Previously, he was a Developer Advocate at StreamNative, Principal DataFlow Field Engineer at Cloudera, a Senior Solutions Engineer at Hortonworks, a Senior Solutions Architect at AirisData, a Senior Field Engineer at Pivotal and a Team Leader at HPE. He blogs for DZone, where he is the Big Data Zone leader, and runs a popular meetup in Princeton & NYC on Big Data, Cloud, IoT, deep learning, streaming, NiFi, the blockchain, and Spark. Tim is a frequent speaker at conferences such as ApacheCon, DeveloperWeek, Pulsar Summit and many more. He holds a BS and MS in computer science
expert thumbnail

Alejandro Duarte

Looking for my next challenge

Alejandro Duarte is a software engineer, published author, and speaker. He has been programming computers since the mid-1990s and has never stopped. Starting with BASIC, Alejandro transitioned to C, C++, and Java during his academic years at the National University of Colombia. He relocated first to the UK and then to Finland to deepen his involvement in the open-source software industry. Alejandro has contributed extensively to the Java and database communities through articles, videos, and talks that have collectively reached millions of views. His educational content covers a wide range of technologies from backend to frontend, helping companies build stronger connections with software developers. You can contact him through his personal blog at programmingbrain.com or on social media platforms such as LinkedIn.

The Latest IoT Topics

article thumbnail
MQTT, Kafka, NATS, or Zenoh? Choosing Edge-to-Cloud Messaging by Traffic Pattern
Telemetry, control, site sync, and delivery to people have different physics. Here's how MQTT, Kafka, NATS, Zenoh, event mesh, and last-mile platforms map onto them.
October 27, 2026
by Kai Wähner DZone Core CORE
· 1,360 Views
article thumbnail
How to Migrate From C/C++ to Rust: A Practical Guide for Embedded IoT Systems
Discover how to migrate embedded C and C++ systems to Rust using one of the three migration strategies to make your project more reliable and compliant.
October 22, 2026
by Andrew Davies
· 1,329 Views
article thumbnail
When One Docker Swarm Replica Became Unreachable Over an Overlay Network: A Production Case With Traefik
One Docker Swarm replica became unreachable to Traefik over the overlay network, while the service remained available through its healthy replica.
October 13, 2026
by Denis Tiumentsev
· 1,502 Views · 1 Like
article thumbnail
Documentation Debt Is the Real Risk in Long-Lived Network Infrastructure
Networks accrue "doc debt" like code accrues technical debt: change that ships without updating the record widens the gap-until a stale diagram causes an outage.
October 7, 2026
by Savni Sandbhor
· 1,862 Views · 1 Like
article thumbnail
Building IoT Time-Series Applications With Java and Apache IoTDB
Apache IoTDB targets device-oriented time-series workloads. Eclipse JNoSQL 1.1.18 lets Java devs use it with TimeSeriesTemplate and Jakarta Data repositories.
October 6, 2026
by Otavio Santana DZone Core CORE
· 1,863 Views · 3 Likes
article thumbnail
Beyond Clicking Buttons: Build a Browser Agent That Verifies Its Results With Playwright MCP
A browser agent uses Playwright MCP to verify outcomes, not just click. Explicit checks and evidence distinguish success from failure or uncertainty.
October 2, 2026
by Akhil Madineni DZone Core CORE
· 1,212 Views · 3 Likes
article thumbnail
Jakarta Batch in Practice: Reliable Chunk-Oriented Processing for Enterprise Workloads
Jakarta Batch gives enterprise apps a standard model for long-running data processing with jobs, steps, readers, processors, writers, checkpoints, and tunable execution.
September 29, 2026
by Otavio Santana DZone Core CORE
· 1,649 Views · 3 Likes
article thumbnail
Distributing Massive AI Models With Network-Layer Multicast
This article explains why network-layer multicast solves the bottleneck, how it works in practice, and where it still falls short.
September 15, 2026
by Vijayananda jayaraman
· 1,977 Views · 4 Likes
article thumbnail
Best Practices for Handling Bad Data in Stream Processing Platforms
Learn best practices for handling bad data in stream processing, from schema validation and duplicate detection to dead-letter queues, monitoring, and data lineage.
September 2, 2026
by Gautam Goswami DZone Core CORE
· 2,620 Views · 3 Likes
article thumbnail
Securing Branch Networks With Firewalls, VPNs, IDS/IPS, and Identity-Based Access
Deny-by-default firewall. VPN scoped tight. IDS behind egress. Identity drives VLAN, not subnet, shifting security decisions from location to identity.
August 5, 2026
by Kamal chand Narra
· 1,869 Views · 1 Like
article thumbnail
Why Do Some Proxies Work Fine for Search But Fail Once You Start Filtering Results?
Root searches are cached and easy to access. Filtering forces requests to hit the backend database directly, triggering stricter anti-bot checks that block basic proxies.
July 21, 2026
by xiyun chen
· 2,686 Views · 1 Like
article thumbnail
Architecting Autonomous Network Ecosystems: From Reactive Monitoring to Agentic AI Orchestration
A strategic blueprint for integrating sophisticated multi-agent systems designed to drive proactive, zero-touch network operations.
July 15, 2026
by Daniel Oh DZone Core CORE
· 5,058 Views · 3 Likes
article thumbnail
From Polling to PubSub: Building an Asynchronous OPC UA Stack in Python
The architectural design and engineering required to build a native, asynchronous OPC UA Pub/Sub (IEC 62541-14) stack in Python for the open-source opcua-asyncio library.
July 3, 2026
by Harshith Narasimhan Srivatsa
· 2,699 Views · 2 Likes
article thumbnail
Solving Data Traffic Jams in Your Network
Not even data likes a lengthy commute. In this article, let’s explore how to solve congestion chaos with tighter infrastructure.
June 22, 2026
by Sascha Neumeier
· 1,296 Views · 3 Likes
article thumbnail
Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot
Learn how Kotlin Coroutines improve Spring Boot Kafka batch processing with parallel execution, resource throttling, and faster database operations.
June 16, 2026
by Erkin Karanlık
· 3,326 Views · 2 Likes
article thumbnail
Bringing Intelligence Closer to the Source: Why Real-Time Processing is the Heart of Edge AI
Edge AI runs AI on devices for real-time decisions, cutting latency, boosting privacy, lowering costs, and working without internet for faster, reliable systems.
May 26, 2026
by Jitendra Bafna
· 3,338 Views · 1 Like
article thumbnail
Building Enterprise-Grade Real-Time IoT Dashboards with Vue 3, MQTT, and Kafka
Event-driven architecture using MQTT (device communication) → Kafka (durable streams) → WebSocket (browser push) → Vue 3 (reactive UI).
May 26, 2026
by Venkata Sandeep Dhullipalla
· 3,674 Views · 1 Like
article thumbnail
Scaling Cloud Data Automation: A Practical Guide to Open Table Formats
Leverage open table formats with cloud automation and scalable analytics to build reliable, high-performance data platforms.
May 25, 2026
by Sandeep Batchu
· 3,820 Views · 1 Like
article thumbnail
Edge Computing in Utility IoT: Two Architecture Patterns That Actually Work
In this article, we break down edge architecture patterns that fit modern utility infrastructure when power flows both ways.
May 22, 2026
by Yevheniia Mala
· 4,799 Views · 1 Like
article thumbnail
The Network Attach Problem Nobody Warns You About
NB-IoT, Cat-M, and now RedCap all surface the same mass attach problem at scale. Here's what it is, why RedCap doesn't escape it, and what to fix before activation day.
May 14, 2026
by SESHA KIRAN GONABOYINA
· 2,739 Views · 1 Like
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • ...
  • Next
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook
×