<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: mxsm</title>
    <description>The latest articles on DEV Community by mxsm (@mxsm).</description>
    <link>https://dev.to/mxsm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F950931%2F920db330-5636-4c40-8293-211c5ea0a477.jpeg</url>
      <title>DEV Community: mxsm</title>
      <link>https://dev.to/mxsm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mxsm"/>
    <language>en</language>
    <item>
      <title>Inside RocketMQ-Rust Broker: From Request Dispatch to Storage and Shutdown</title>
      <dc:creator>mxsm</dc:creator>
      <pubDate>Thu, 15 Oct 2026 15:36:56 +0000</pubDate>
      <link>https://dev.to/mxsm/inside-rocketmq-rust-broker-from-request-dispatch-to-storage-and-shutdown-5c64</link>
      <guid>https://dev.to/mxsm/inside-rocketmq-rust-broker-from-request-dispatch-to-storage-and-shutdown-5c64</guid>
      <description>&lt;p&gt;A message broker becomes easier to understand when you follow a request across its boundaries: the network entry point, the business processor, the storage operation, and the response. Background work adds another question: who owns the operation after the initial request stops running?&lt;/p&gt;

&lt;p&gt;This article follows those boundaries in the Broker implementation of &lt;a href="https://github.com/mxsm/rocketmq-rust/tree/9aae6af71fb9e8e3149aa8201bb840dbc0082418" rel="noopener noreferrer"&gt;mxsm/rocketmq-rust&lt;/a&gt;. Every source link is pinned to commit &lt;code&gt;9aae6af71fb9e8e3149aa8201bb840dbc0082418&lt;/code&gt;, inspected on October 15, 2026. The scope is a source walkthrough, rather than a benchmark, deployment guide, or claim of feature parity with other implementations.&lt;/p&gt;

&lt;p&gt;The most useful starting point is the relationship between three concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transport admits requests and carries responses&lt;/li&gt;
&lt;li&gt;Broker processors apply messaging and administrative behavior&lt;/li&gt;
&lt;li&gt;Store implementations handle message persistence and retrieval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Runtime composition connects these concerns. Lifecycle code determines when they become available and how their work is stopped.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start with composition, then follow a request
&lt;/h2&gt;

&lt;p&gt;The Broker is assembled from several groups of responsibilities. &lt;code&gt;BrokerComposition&lt;/code&gt; contains runtime state, a request pipeline, a data plane, a control plane, and metadata. This gives readers a practical map: request routing belongs in a different area from control-plane coordination or metadata ownership. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/broker_runtime/composition.rs" rel="noopener noreferrer"&gt;composition.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Startup makes the connections concrete. &lt;code&gt;start_basic_service&lt;/code&gt; starts the message store, checks that the transactional message service exists, initializes the deferred lifecycle, and prepares the processors. It then constructs an &lt;code&gt;AuthorizedCommandDispatcher&lt;/code&gt; with shared admission, telemetry, and a resource budget.&lt;/p&gt;

&lt;p&gt;The resulting dispatcher is published as the canonical dispatcher. Both normal and fast remoting servers receive clones of the same &lt;code&gt;Arc&lt;/code&gt;. That detail is valuable when reading the code: two listeners do not imply two independently assembled Broker routing graphs. The startup path also waits for listener readiness and records completed startup components. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/broker_runtime/request_pipeline/startup.rs" rel="noopener noreferrer"&gt;request_pipeline/startup.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A simplified reading map is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Transport listener
  -&amp;gt; shared authorized dispatcher
  -&amp;gt; Broker request-code router
  -&amp;gt; operation-specific processor
  -&amp;gt; Store capability or other Broker service
  -&amp;gt; response action
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sketch describes responsibility boundaries. Individual requests can take different routes, including deferred completion.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Request codes select business processors
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;BrokerRequestProcessor&amp;lt;P&amp;gt;&lt;/code&gt; holds a request-code map and an optional default processor. In the assembled Broker, &lt;code&gt;BrokerProcessorType&lt;/code&gt; is an enum covering processors such as Send, Pull, Pop, Ack, QueryMessage, ClientManage, ConsumerManage, EndTransaction, and AdminBroker.&lt;/p&gt;

&lt;p&gt;The enum implements the transport &lt;code&gt;RequestProcessor&lt;/code&gt; contract and delegates to the selected processor's &lt;code&gt;process_shared&lt;/code&gt; method. The code-indexed router also participates in request rejection, ordering, and response observation. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/processor/dispatcher.rs" rel="noopener noreferrer"&gt;dispatcher.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The registration code is especially useful for discovering behavior. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SendMessage&lt;/code&gt;, &lt;code&gt;SendMessageV2&lt;/code&gt;, and &lt;code&gt;SendBatchMessage&lt;/code&gt; share the Send processor&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PullMessage&lt;/code&gt; and &lt;code&gt;LitePullMessage&lt;/code&gt; share the Pull processor&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AckMessage&lt;/code&gt; and &lt;code&gt;BatchAckMessage&lt;/code&gt; share the Ack processor&lt;/li&gt;
&lt;li&gt;Consumer-offset operations are registered with ConsumerManage&lt;/li&gt;
&lt;li&gt;AdminBroker is installed as the default processor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These mappings are visible in &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/broker_runtime/request_pipeline.rs" rel="noopener noreferrer"&gt;request_pipeline.rs&lt;/a&gt;. A registered route identifies the handler to investigate; it does not, by itself, establish the completeness of every behavior behind that handler.&lt;/p&gt;

&lt;p&gt;Authentication is also explicit at this boundary. Startup requires either an initialized authentication runtime or a validated configuration with authentication and authorization disabled. For ordinary requests, the router checks its authentication state before dispatching to a leaf processor. Privileged maintenance requests have separate routing and policy checks. This makes security configuration part of assembling the request path, rather than an assumption attached to a handler name.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Follow a send through the Store boundary
&lt;/h2&gt;

&lt;p&gt;The Store layer exposes a &lt;code&gt;MessageStore&lt;/code&gt; enum that owns the selected concrete backend. Its variants include a local-file store and, behind the &lt;code&gt;rocksdb_store&lt;/code&gt; feature, a RocksDB store. The ownership comment is important: shared consumers should receive narrower Store capabilities while the application lifecycle retains the mutable root owner. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-store/src/store_ports.rs" rel="noopener noreferrer"&gt;store_ports.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Send processor's structured Store helper operates through &lt;code&gt;MessageAppender&amp;lt;M&amp;gt;&lt;/code&gt;. It awaits an append inside the admitted request task and converts the result into a &lt;code&gt;RemotingResponse&lt;/code&gt; wrapped in &lt;code&gt;ResponseAction::Reply&lt;/code&gt;. A separate completion token records the timing class for send-hook completion. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/processor/send_message_processor/structured_store.rs" rel="noopener noreferrer"&gt;structured_store.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One subtlety deserves attention: cancellation stops waiting and suppresses a reply, but cannot prove that an operation already handed to the backend did not commit. That distinction matters when reasoning about a producer timeout. A missing response is insufficient evidence that the message was never stored. Client retry and application deduplication decisions therefore need to account for uncertain outcomes.&lt;/p&gt;

&lt;p&gt;In the local-file write path, &lt;code&gt;put_message_shared&lt;/code&gt; checks Store availability and writability, runs pre-put hooks, handles relevant validation and quota reservations, and calls &lt;code&gt;commit_log.put_message&lt;/code&gt;. When the returned result is successful, it notifies the reput service that a new message is available. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-store/src/message_store/local_file_message_store/write_path.rs" rel="noopener noreferrer"&gt;write_path.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This separates the append operation from subsequent dispatch work. The exact durability meaning of a result still requires inspecting the commit-log implementation and the active configuration; the existence of an append call alone is insufficient to establish a durability guarantee.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Distinguish physical storage from consumer position
&lt;/h2&gt;

&lt;p&gt;The local-file read path helps explain the storage model. It locates a consume queue by topic and queue ID, checks its offset range, iterates consume-queue entries, and uses their physical offsets and sizes to retrieve messages from the commit log. Filtering can happen against consume-queue information and, when required, the commit-log payload. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-store/src/message_store/local_file_message_store/read_path.rs" rel="noopener noreferrer"&gt;read_path.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a reader, the important distinction is between a consumer-facing queue position and a physical location in the log. Keeping those coordinates separate makes offset checks and retrieval code much easier to follow.&lt;/p&gt;

&lt;p&gt;There is also an explicit reput dispatch pipeline. It can execute dispatcher lanes concurrently when parallel dispatch is enabled and every dispatcher supports it. Before cloning a batch for those lanes, it attempts to acquire a retained-byte budget. If that budget is unavailable, it falls back to serial dispatch. In the parallel path, the published frontier advances after the joined lane futures complete. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-store/src/message_store/local_file_message_store/reput_pipeline.rs" rel="noopener noreferrer"&gt;reput_pipeline.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a useful concurrency pattern to study: parallel work has an explicit memory cost, a fallback path, and a defined point for publishing progress. Source inspection establishes that structure; measuring its throughput or latency requires a separate experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Consumption includes owned waiting
&lt;/h2&gt;

&lt;p&gt;A consumer request can produce a response immediately or wait for a later opportunity to return data. The Pull processor represents this distinction explicitly. Its supported processing path handles a reply or a suspension result. Suspension goes through deferred preparation and registration; successful registration returns &lt;code&gt;ResponseAction::Deferred&lt;/code&gt;. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/processor/pull_message_processor.rs" rel="noopener noreferrer"&gt;pull_message_processor.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When a deferred Pull resumes, it reruns the canonical Pull business path with further suspension disabled. The wake reasons include message arrival, timeout, and forced refresh. This is useful because the resumed request obtains a fresh business result instead of simply replaying an earlier empty response. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/processor/pull_message_processor/resume.rs" rel="noopener noreferrer"&gt;pull_message_processor/resume.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The runtime owns this waiting machinery. &lt;code&gt;BrokerDeferredLifecycle&lt;/code&gt; groups admission, a generation handoff, deferred services for Pull, Pop, Notification, and PopLite, and an optional producer with its task group. Configuration establishes entry and retained-byte limits. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/broker_runtime/deferred.rs" rel="noopener noreferrer"&gt;deferred.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Pull Store capability offers a smaller ownership example. It retains a &lt;code&gt;Weak&amp;lt;dyn PullMessageStorePort&amp;gt;&lt;/code&gt; and upgrades that reference when accessing the provider. If the provider is gone, the operation can return &lt;code&gt;MessageStoreUnavailable&lt;/code&gt;. The policy object separately projects the Broker and Store settings needed by Pull. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/processor/pull_message_processor/capability.rs" rel="noopener noreferrer"&gt;pull_message_processor/capability.rs&lt;/a&gt;. Reading the policy, context, and capability together helps answer which decisions belong to the processor and which operations depend on another service. It also shows why following ownership is useful alongside following function calls: a callable interface still needs a live provider.&lt;/p&gt;

&lt;p&gt;Pull and Pop still have distinct processors and associated operations. Ack and change-invisibility routes are useful next stops for studying the Pop side. Treating every consumption mode as an identical read would hide those protocol-specific responsibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Shutdown reveals the ownership model
&lt;/h2&gt;

&lt;p&gt;Shutdown is particularly revealing because it must reconcile listeners, running requests, deferred work, background services, and storage ownership.&lt;/p&gt;

&lt;p&gt;The Broker uses an absolute shutdown deadline and component reports. Its shutdown sequence seals deferred producer routes, shuts down tracked producer tasks, closes deferred registries, stops remoting servers, and shuts down request-processor tasks. It then checks deferred registry state again and proceeds through additional service cleanup. See &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/9aae6af71fb9e8e3149aa8201bb840dbc0082418/rocketmq-broker/src/broker_runtime/lifecycle.rs" rel="noopener noreferrer"&gt;lifecycle.rs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Later, the shutdown path waits within the deadline for shared Store ownership to be released. It attempts graceful Store shutdown when mutable access is available. Crucially, the root Store owner is removed only when shutdown completes; failures or timeouts retain it for a later attempt.&lt;/p&gt;

&lt;p&gt;That behavior connects the architecture's ownership choices to an operational concern. A background task retaining Store access can affect shutdown progress. Reports distinguish outcomes so that cleanup problems are observable rather than automatically treated as success.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical source-reading exercise
&lt;/h2&gt;

&lt;p&gt;To explore further, pick one request code and trace four things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where the code is registered and which processor receives it&lt;/li&gt;
&lt;li&gt;Which policy and service capabilities the processor uses&lt;/li&gt;
&lt;li&gt;Whether completion is immediate, Store-backed, or deferred&lt;/li&gt;
&lt;li&gt;Which lifecycle owner stops any work the request leaves behind&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For an ordinary send, this leads from the request router into the appender and commit log. For a waiting Pull, it leads into deferred registration, resumption, and cleanup. These paths provide a grounded introduction to the Broker while leaving performance, compatibility, and deployment readiness as separate questions requiring their own evidence.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI disclosure: This article was drafted by AI and checked by AI against the linked source files at the pinned commit. It does not report a runtime test or benchmark.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>architecture</category>
      <category>backend</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Understanding the RocketMQ-Rust Runtime Architecture</title>
      <dc:creator>mxsm</dc:creator>
      <pubDate>Sat, 10 Oct 2026 01:02:25 +0000</pubDate>
      <link>https://dev.to/mxsm/understanding-the-rocketmq-rust-runtime-architecture-6ci</link>
      <guid>https://dev.to/mxsm/understanding-the-rocketmq-rust-runtime-architecture-6ci</guid>
      <description>&lt;p&gt;A message broker runs many kinds of work at once: network requests, periodic maintenance, storage operations, metadata writes, and shutdown cleanup. Executing a future is only one part of the problem. The application also needs to know who owns that work, when to reject more of it, and what remains after a timeout.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rocketmq-runtime&lt;/code&gt; builds on Tokio to connect those decisions. Its central design is explicit ownership: the application owns the runtime, components own tracked tasks, and resource permits follow the work that actually retains capacity.&lt;/p&gt;

&lt;p&gt;This article follows the project's architecture animation through seven stages: boot, spawn, schedule, block, budget, persist, and shutdown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F931v5cv4fnt94xu9pr2o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F931v5cv4fnt94xu9pr2o.gif" alt="RocketMQ-Rust runtime architecture showing startup, task ownership, scheduling, shared blocking lanes, resource budgets, metadata persistence, and shutdown" width="600" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The project's &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/e9b9b57d1134b40d1165a8a650b1bb85c2c42d02/resources/rocketmq-runtime-architecture.svg" rel="noopener noreferrer"&gt;original architecture SVG&lt;/a&gt; uses a 32-second animation to explain relationships. The animation timing does not represent measured execution time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scope:&lt;/strong&gt; This is a source-based walkthrough of &lt;a href="https://github.com/mxsm/rocketmq-rust/commit/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6" rel="noopener noreferrer"&gt;commit &lt;code&gt;5cdc853&lt;/code&gt;&lt;/a&gt;, checked on October 10, 2026. It describes the repository snapshot, which may differ from a published crate release. No benchmarks or tests were run for this article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI disclosure:&lt;/strong&gt; This article was generated by an AI assistant using the linked project documentation and source code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the diagram as two trees and shared execution capacity
&lt;/h2&gt;

&lt;p&gt;Three structures organize the runtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;task ownership tree&lt;/strong&gt; determines which component admits, tracks, and shuts down work&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;resource-budget tree&lt;/strong&gt; accounts for explicitly reserved counts and retained bytes&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;shared blocking lanes&lt;/strong&gt; admit blocking closures through bounded capacity and maintain a separate task registry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every &lt;code&gt;component(...)&lt;/code&gt; call creates a child &lt;code&gt;TaskGroup&lt;/code&gt;. A child context can create further children, and a group can own both tasks and other groups. Cloning a context shares its existing group.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TaskKind&lt;/code&gt; labels a task; it does not create another ownership level. An &lt;code&gt;OperationContext&lt;/code&gt; adds cancellation and a deadline to work within an existing component group. A &lt;code&gt;ScheduledTaskGroup&lt;/code&gt;, by contrast, owns a child group for its driver and runs.&lt;/p&gt;

&lt;p&gt;Keep resource accounting separate from this hierarchy. Giving a task an owner does not automatically account for every allocation it makes. The &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/ARCHITECTURE.md" rel="noopener noreferrer"&gt;architecture contracts&lt;/a&gt; make that boundary explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Boot with an application-owned runtime
&lt;/h2&gt;

&lt;p&gt;The recommended construction path is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RuntimeConfig → RuntimeOwner::plan → build → RootServiceContext&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Planning validates configuration without starting Tokio or discovering system resources. Building performs memory-limit discovery and constructs the runtime.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RuntimeOwner&lt;/code&gt; owns the execution environment and shared resources. Components receive &lt;code&gt;ChildServiceContext&lt;/code&gt;, or a narrower capability such as &lt;code&gt;TaskSpawner&lt;/code&gt;. &lt;code&gt;RuntimeHandle&lt;/code&gt; is an internal implementation detail, not the public integration API.&lt;/p&gt;

&lt;p&gt;This finite example comes from the &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/README.md#runtime-ownership-and-quick-start" rel="noopener noreferrer"&gt;runtime README&lt;/a&gt;. It registers a service and immediately exercises cooperative shutdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rocketmq_runtime&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;RuntimeConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RuntimeOwner&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RuntimeOwner&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;RuntimeConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;broker_default&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;broker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="nf"&gt;.root_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"broker"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cancellation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;broker&lt;/span&gt;&lt;span class="nf"&gt;.task_group&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.cancellation_token&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;broker&lt;/span&gt;&lt;span class="nf"&gt;.spawn_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"heartbeat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cancellation&lt;/span&gt;&lt;span class="nf"&gt;.cancelled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Finish any ordered asynchronous cleanup here.&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="nf"&gt;.shutdown_runtime_blocking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="nf"&gt;.is_healthy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="nf"&gt;.to_json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A real entrypoint first runs startup and service logic through &lt;code&gt;owner.block_on(...)&lt;/code&gt;. It then consumes the owner outside the Tokio context to shut down the runtime. The &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-broker/src/bin/broker_bootstrap_server.rs" rel="noopener noreferrer"&gt;Broker entrypoint&lt;/a&gt; follows this pattern and checks the resulting report.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Spawn with a cancellation contract
&lt;/h2&gt;

&lt;p&gt;Task submission must coordinate with shutdown. Otherwise, shutdown could observe an empty registry just before another thread submits work.&lt;/p&gt;

&lt;p&gt;The task group's spawn gate serializes registration with shutdown transitions. Metadata and a tracker token are registered under the gate; dispatch to Tokio follows outside it. If an abort arrives before the task handle is installed, that request is still honored.&lt;/p&gt;

&lt;p&gt;Cancellation propagates from a parent group to its descendants. Cancelling one child does not cancel its parent or siblings. Dropping a context handle is insufficient for graceful shutdown because active tasks can keep the group alive.&lt;/p&gt;

&lt;p&gt;Choose a submission method by deciding what cancellation should do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;spawn_service&lt;/code&gt;: the service observes cancellation and performs its own ordered cleanup&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spawn_cancellable_service&lt;/code&gt;: owner cancellation drops the future, appropriate when cancellation is safe&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spawn_operation&lt;/code&gt;: work observes both owner cancellation and the operation's cancellation or deadline&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spawn_draining_operation&lt;/code&gt;: accepted work can continue after owner cancellation, while operation cancellation, its deadline, and group shutdown still bound it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For request-scoped work, use an operation under a stable component rather than creating a new component per request. Also distinguish &lt;code&gt;cancel()&lt;/code&gt;, which broadcasts a signal, from &lt;code&gt;shutdown(...)&lt;/code&gt;, which closes admission and waits for evidence. See the &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/README.md#task-scopes-and-cancellation" rel="noopener noreferrer"&gt;task contracts&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Schedule with an explicit backlog policy
&lt;/h2&gt;

&lt;p&gt;Periodic work becomes interesting when one run takes longer than its period. The scheduler makes the response explicit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fixed_delay&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wait one period after the previous run finishes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fixed_rate_no_overlap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep a fixed cadence without overlapping runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fixed_rate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep a fixed cadence with an explicit concurrency bound&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Configuration selects the timing model, and the execution policy must agree. When all fixed-rate run slots are occupied, &lt;code&gt;Skip&lt;/code&gt; discards the tick, &lt;code&gt;CoalesceLatest&lt;/code&gt; retains one pending run, and &lt;code&gt;BoundedCatchUp(n)&lt;/code&gt; retains a bounded backlog.&lt;/p&gt;

&lt;p&gt;For example, a refresh that only needs the latest state may tolerate coalescing. Maintenance that should rest between executions is a better candidate for fixed delay. These are application decisions: a scheduler cannot decide whether skipped work is acceptable.&lt;/p&gt;

&lt;p&gt;Drivers and runs remain tracked under the scheduler's group. &lt;code&gt;max_run_time&lt;/code&gt; can drop a run's future, but the application must still reason about external side effects already triggered. The &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/README.md#scheduled-tasks" rel="noopener noreferrer"&gt;scheduling documentation&lt;/a&gt; also describes drift and run metrics.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Keep blocking capacity until the closure exits
&lt;/h2&gt;

&lt;p&gt;Components access managed lanes through &lt;code&gt;storage_io()&lt;/code&gt;, &lt;code&gt;metadata_io()&lt;/code&gt;, and &lt;code&gt;cpu_crypto()&lt;/code&gt;. The lanes share one global admission budget per owner, with additional lane-specific concurrency and queue bounds. Cloning an executor does not create another pool.&lt;/p&gt;

&lt;p&gt;Two timeout settings cover different phases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;queue_timeout&lt;/code&gt; bounds the wait for execution capacity&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;task_timeout&lt;/code&gt; bounds the caller's wait after admission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither can stop an already-running blocking closure.&lt;/p&gt;

&lt;p&gt;Consider a filesystem operation that stalls. Its caller times out, but the underlying closure continues. Releasing the permit at that point would admit another operation while the first still consumes capacity. Repeated timeouts could make actual concurrency exceed the configured limit.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/src/blocking/executor.rs" rel="noopener noreferrer"&gt;executor implementation&lt;/a&gt; therefore lets the real closure retain its permit and task record until exit. An abandoned running submission can appear as &lt;code&gt;TimedOutStillRunning&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Long-lived blocking loops need their own owner and stop/join protocol. The managed lanes reject &lt;code&gt;BlockingKind::LongRunning&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Account for the full lifetime of retained data
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;RuntimeResources&lt;/code&gt; provides the shared process budget. Component budgets enforce limits along their ancestor chain; reservations use atomic reserve-and-rollback so a failed ancestor check does not leave partial reservations behind.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ResourcePermit&lt;/code&gt; holds a reservation through RAII. A configured control reserve can keep data work from consuming capacity intended for control work.&lt;/p&gt;

&lt;p&gt;The subtle part is dequeue behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;recv()&lt;/code&gt; and &lt;code&gt;try_pop()&lt;/code&gt; release the permit when the item leaves the queue&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recv_budgeted()&lt;/code&gt; and &lt;code&gt;try_pop_budgeted()&lt;/code&gt; return a &lt;code&gt;BudgetedItem&lt;/code&gt; that retains the permit during processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suppose a large payload leaves a queue and spends another second being processed. If the budget is intended to cover queued and in-flight data, releasing its permit at dequeue understates retained work. The budgeted variants let the reservation follow that lifetime.&lt;/p&gt;

&lt;p&gt;These are explicit accounting limits, not an automatic ceiling on process RSS. Untracked allocations, caller-retained copies, and runtime overhead remain outside the ledger. Memory-limit discovery helps configure budgets; deployment sizing still needs measurement and headroom. The &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/README.md#resource-budgets-and-queues" rel="noopener noreferrer"&gt;budget and queue contracts&lt;/a&gt; explain the transfer rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Separate metadata acceptance from durability
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;MetadataIoActor&lt;/code&gt; accepts immutable snapshots and coordinates their generations. It uses the owner's shared metadata lane for actual writes, with bounded pending operations and bytes.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;Accepted&lt;/code&gt; submission provides a receipt. It does not establish durability. The caller must wait for that receipt's persistence result, or use a durable submission API and inspect the outcome.&lt;/p&gt;

&lt;p&gt;Queued generations for one logical resource can coalesce. A later durable generation can satisfy an earlier waiter. This suits complete snapshots where newer state includes earlier changes; it is unsuitable as a substitute for preserving every append-only log record.&lt;/p&gt;

&lt;p&gt;By default, the actor writes one resource at a time. &lt;code&gt;with_max_concurrent_writes(n)&lt;/code&gt; permits bounded concurrency between independent resources, still limited by the metadata lane. Generations of one resource remain serialized.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/src/metadata_io/filesystem.rs" rel="noopener noreferrer"&gt;filesystem implementation&lt;/a&gt; writes a temporary file, synchronizes it, replaces the target, and synchronizes the parent directory on supported platforms before advancing durable generation.&lt;/p&gt;

&lt;p&gt;The closure retains its snapshot and budget permit through real completion, even if its observer times out. Consequently, a timeout does not prove rollback or justify treating the write as never having happened. Unknown outcomes require reconciliation. Target coordination is process-local and does not provide a cross-process lock or generic crash-recovery guarantee. See the &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/README.md#metadata-persistence" rel="noopener noreferrer"&gt;persistence contract&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Shut down against one deadline and inspect the evidence
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ServiceLifecycle&lt;/code&gt; separates readiness, liveness, and shutdown coordination. Its first shutdown request freezes an absolute &lt;code&gt;ShutdownDeadline&lt;/code&gt;; subsequent requests cannot extend it.&lt;/p&gt;

&lt;p&gt;Passing that deadline through components and the owner prevents a common mistake: granting each shutdown layer a fresh timeout and accidentally multiplying the total exit budget. The Broker passes the lifecycle deadline to &lt;code&gt;shutdown_runtime_blocking_until(...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A task group closes admission, broadcasts cancellation, and starts child shutdowns concurrently with waiting for its own tasks. Remaining tracked tasks are aborted at the deadline. The owner additionally accounts for blocking work.&lt;/p&gt;

&lt;p&gt;The reports distinguish several kinds of evidence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Task completion:&lt;/strong&gt; the registered future was destroyed; this alone does not prove business success&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Abort confirmation:&lt;/strong&gt; requesting abort and confirming destruction are different observations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocking completion:&lt;/strong&gt; a closure may still run after its caller stops waiting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Durable metadata completion:&lt;/strong&gt; the receipt establishes the persistence result independently of task exit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;ShutdownReport::is_healthy()&lt;/code&gt; requires zero leaked, failed, panicked, timed-out, and still-running-blocking counts, plus healthy children. An &lt;code&gt;aborted&lt;/code&gt; count alone does not make the report unhealthy.&lt;/p&gt;

&lt;p&gt;Use absolute-deadline APIs when composing a shared budget. Some relative operation waits allow up to one extra second to confirm aborted futures were destroyed. Even absolute deadlines are not hard real-time guarantees: runtime starvation or blocking destructors can delay timer polling.&lt;/p&gt;

&lt;p&gt;Explicitly stop admission and drain final I/O in the application's required order. &lt;code&gt;Drop&lt;/code&gt; and immediate shutdown are fallback paths, and their reports cannot establish that all asynchronous cleanup finished. These details are documented in the &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/README.md#service-lifecycle-and-shutdown" rel="noopener noreferrer"&gt;shutdown contracts&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical integration checklist
&lt;/h2&gt;

&lt;p&gt;When reviewing a component, follow the same path as the animation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does it receive an application-owned context?&lt;/li&gt;
&lt;li&gt;Is dropping each cancellable future safe?&lt;/li&gt;
&lt;li&gt;What happens when periodic work falls behind?&lt;/li&gt;
&lt;li&gt;Does blocking capacity remain held after observer timeout?&lt;/li&gt;
&lt;li&gt;Does accounting cover payloads after dequeue?&lt;/li&gt;
&lt;li&gt;Does the caller distinguish metadata acceptance from durability?&lt;/li&gt;
&lt;li&gt;Does cleanup share one deadline and inspect incomplete-work reports?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For operational visibility, V2 diagnostics label sections as &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;subtree&lt;/code&gt;, or &lt;code&gt;process_shared&lt;/code&gt;. A missing input produces an absent section rather than an apparently empty one. Detail-scan budgets do not bound full aggregate collection, and snapshots are not globally atomic across groups. Prefer sanitized views for authenticated operational endpoints. &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/README.md#diagnostics" rel="noopener noreferrer"&gt;Diagnostics documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The recurring question is what “finished” means at each boundary. A caller returning, a future being destroyed, a closure exiting, and a generation becoming durable provide different evidence. RocketMQ-Rust's runtime makes those distinctions explicit so component code can choose the right contract.&lt;/p&gt;

&lt;p&gt;Further reading: &lt;a href="https://github.com/mxsm/rocketmq-rust" rel="noopener noreferrer"&gt;project repository&lt;/a&gt;, &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/README.md" rel="noopener noreferrer"&gt;runtime README&lt;/a&gt;, and &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/5cdc853a2279fab77a7067647a0d5e3f0bbf85b6/rocketmq-runtime/ARCHITECTURE.md" rel="noopener noreferrer"&gt;architecture invariants&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>architecture</category>
      <category>opensource</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>RocketMQ-Rust: what should happen when message three fails?</title>
      <dc:creator>mxsm</dc:creator>
      <pubDate>Thu, 08 Oct 2026 05:04:03 +0000</pubDate>
      <link>https://dev.to/mxsm/rocketmq-rust-what-should-happen-when-message-three-fails-3k7h</link>
      <guid>https://dev.to/mxsm/rocketmq-rust-what-should-happen-when-message-three-fails-3k7h</guid>
      <description>&lt;p&gt;RocketMQ-Rust is a community Rust implementation of Apache RocketMQ. Its basic architecture separates discovery in NameServer, message storage and delivery in the Broker, and business processing in client applications. The project's first-message tutorial is a useful starting point for examining that last boundary.&lt;/p&gt;

&lt;p&gt;Consider this small extension to the tutorial: a consumer receives five events from one queue. Events 1 and 2 update the application database successfully. Event 3 fails. Events 4 and 5 have not run.&lt;/p&gt;

&lt;p&gt;What progress is safe to record?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Advancing beyond all five events risks skipping unfinished work when consumption resumes&lt;/li&gt;
&lt;li&gt;Retrying the batch can repeat the already completed updates for events 1 and 2&lt;/li&gt;
&lt;li&gt;Advancing only through the successfully processed prefix requires tracking progress for that queue, rather than treating the batch as a single success&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important distinction is between receiving an event, completing its business effect, and persisting consumption progress. Those steps can fail independently.&lt;/p&gt;

&lt;p&gt;RocketMQ-Rust's &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-website/docs/getting-started/quick-start.md#4-understand-the-result" rel="noopener noreferrer"&gt;v1.0.0 tutorial&lt;/a&gt; makes a related detail explicit: LitePull's &lt;code&gt;commit_all&lt;/code&gt; updates client offset-store state separately from persistence. The example's &lt;code&gt;OFFSET_COMMIT_REQUESTED&lt;/code&gt; output reports that the call returned; it does not establish durable Broker acknowledgement or an atomic transaction with your database.&lt;/p&gt;

&lt;p&gt;A useful local exercise is to introduce a deliberate failure at event 3. Record event IDs, queue positions, completed database effects, and the checkpoint that survives a restart. Keep the consumer group unchanged. Check whether successful work repeats and whether unfinished work remains reachable. With multiple queues, examine each queue's progress separately.&lt;/p&gt;

&lt;p&gt;This is also where an application-level event ID and an idempotent database operation become useful: replay should not apply the same business change twice.&lt;/p&gt;

&lt;p&gt;AI disclosure: This post was generated by AI and checked against the linked project documentation. The failure scenario is illustrative, not a report of a test run.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>architecture</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>RocketMQ-Rust: route discovery is only the first connectivity check</title>
      <dc:creator>mxsm</dc:creator>
      <pubDate>Mon, 05 Oct 2026 04:16:06 +0000</pubDate>
      <link>https://dev.to/mxsm/rocketmq-rust-route-discovery-is-only-the-first-connectivity-check-3j5d</link>
      <guid>https://dev.to/mxsm/rocketmq-rust-route-discovery-is-only-the-first-connectivity-check-3j5d</guid>
      <description>&lt;p&gt;A small debugging note from RocketMQ-Rust’s architecture docs:&lt;/p&gt;

&lt;p&gt;NameServer returns topic routes: Broker addresses and queue metadata. In a direct-client deployment, producers and consumers then communicate with the Broker. Message storage and delivery belong to the Broker.&lt;/p&gt;

&lt;p&gt;That distinction matters when a client can fetch a route but still cannot send or consume. A successful NameServer request only confirms discovery worked. It does not prove the advertised Broker address is reachable from that client, or that the Broker can accept writes.&lt;/p&gt;

&lt;p&gt;A useful first check: compare the Broker address returned in the route with the network the client actually runs in. Then investigate Broker connectivity and write readiness separately.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://rocketmqrust.com/docs/architecture/overview#discovery-and-data-ownership" rel="noopener noreferrer"&gt;architecture documentation&lt;/a&gt; explains these boundaries.&lt;/p&gt;

&lt;p&gt;Disclosure: This post was generated with AI assistance and checked against the project documentation.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>architecture</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Understanding RocketMQ Rust Through One Message</title>
      <dc:creator>mxsm</dc:creator>
      <pubDate>Sun, 04 Oct 2026 07:54:25 +0000</pubDate>
      <link>https://dev.to/mxsm/understanding-rocketmq-rust-through-one-message-5d1c</link>
      <guid>https://dev.to/mxsm/understanding-rocketmq-rust-through-one-message-5d1c</guid>
      <description>&lt;p&gt;Architecture and deployment evaluation&lt;/p&gt;

&lt;p&gt;When an order service publishes an event, the interesting question is what happens after the send call returns. Which process accepted the message? What reached storage? What happens if the response disappears, the consumer restarts, or a database update succeeds just before progress is saved?&lt;/p&gt;

&lt;p&gt;Those questions are a useful way to explore RocketMQ-Rust. The project brings the RocketMQ messaging model into a Rust implementation, covering server components as well as client and administration code. Its appeal for systems developers lies in following those responsibilities through a concrete codebase: discovery, transport, persistence, application processing, and recovery.&lt;/p&gt;

&lt;p&gt;This introduction follows that path, explains several design choices, and outlines a practical evaluation. The goal is to help you understand what to investigate before connecting a messaging system to business-critical work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the first major release includes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mxsm/rocketmq-rust/releases/tag/v1.0.0" rel="noopener noreferrer"&gt;RocketMQ-Rust v1.0.0&lt;/a&gt; was published on October 1, 2026. The release identifies NameServer, Controller, Broker, Proxy, the Rust client, and administration tools as core components. It also introduces explicit boundaries for runtime ownership, errors, transport, storage, security, and observability.&lt;/p&gt;

&lt;p&gt;Dashboard Web, MCP, and SRE components are separately packaged, with standalone APIs outside the core 1.0 compatibility surface. A source release also does not establish that every registry artifact is already available: the release notes direct readers to check the asynchronous package and image publication workflows.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/distribution/release-identity.json" rel="noopener noreferrer"&gt;distribution identity&lt;/a&gt; matters, too. RocketMQ-Rust is a community distribution, not an official Apache Software Foundation release. Evaluate its own implementation and support boundaries rather than transferring every assumption about Apache RocketMQ to it.&lt;/p&gt;

&lt;p&gt;There is a documentation detail worth keeping in mind. The live website currently labels its documentation “1.0.0 (development),” while the v1.0.0 release is published. For reproducible experiments, use the tagged source and documentation together. Treat the live website as a learning entry point that can change over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Begin with the three core responsibilities
&lt;/h2&gt;

&lt;p&gt;The simplest useful mental model is NameServer, Broker, and client application.&lt;/p&gt;

&lt;p&gt;NameServer provides discovery. Brokers register their identities, addresses, and topic routing information. A client queries that information to find an appropriate destination. NameServer does not store application message bodies or forward every producer message.&lt;/p&gt;

&lt;p&gt;The Broker owns the message-serving side: validating requests, managing topic and consumer-group metadata, coordinating reads and writes, and managing storage. The Store belongs inside that responsibility boundary; it is not another server that the beginner must launch separately.&lt;/p&gt;

&lt;p&gt;Client applications send or consume messages and manage their own business processing. The Broker does not automatically include an application's database transaction within its own storage operation.&lt;/p&gt;

&lt;p&gt;This division gives troubleshooting a direction. A healthy discovery endpoint can return an address that is unreachable from your application. Conversely, a successful Broker connection says little about whether the consumer's database update completed. The &lt;a href="https://rocketmqrust.com/docs/architecture/overview" rel="noopener noreferrer"&gt;architecture overview&lt;/a&gt; is a useful map of these boundaries.&lt;/p&gt;

&lt;p&gt;Two additional services address different deployment needs. &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-proxy/README.md" rel="noopener noreferrer"&gt;Proxy&lt;/a&gt; exposes the v2 gRPC MessagingService and can connect to a cluster or compose an embedded Broker. &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-controller/README.md" rel="noopener noreferrer"&gt;Controller&lt;/a&gt; coordinates Broker metadata, master election, and replicas. They are not required hops in the direct client-to-Broker path described below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow a message through the system
&lt;/h2&gt;

&lt;p&gt;A producer obtains a topic route, selects a writable queue, and sends a request to the Broker. Protocol code defines the wire representation; transport code handles the connection, framing, admission, and request deadline. The Broker interprets the request against its role, permissions, configuration, and storage state.&lt;/p&gt;

&lt;p&gt;After acceptance, the storage path appends the record and returns an outcome that the Broker maps into a producer response. Background work also builds the structures used to find messages for consumption and queries. These activities can overlap; the response and every possible read view need not advance together.&lt;/p&gt;

&lt;p&gt;A consumer discovers its queues and obtains messages. Only then does application code perform the work that the event represents. Recording consumer progress is another step, with semantics that depend on the consumption model.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-website/docs/architecture/message-lifecycle.md" rel="noopener noreferrer"&gt;tagged message lifecycle guide&lt;/a&gt; makes an important failure case explicit: a message may have been appended even when the producer sees a timeout or certain non-success outcomes. A retry can therefore create duplicate business work unless the application is prepared for it.&lt;/p&gt;

&lt;p&gt;Consider an inventory adjustment. If the consumer updates stock and then crashes before its progress survives, the event can be delivered again. An event identifier and an idempotent database operation can make that replay safe. The right design depends on the business transaction, but the question belongs in the application design from the beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persistence has more than one milestone
&lt;/h2&gt;

&lt;p&gt;The storage architecture separates the primary CommitLog from derived structures. ConsumeQueue connects logical queue positions to physical message records; key indexes support lookup. These structures serve different access paths and can advance at different rates.&lt;/p&gt;

&lt;p&gt;The 1.0 storage contracts also distinguish accepted bytes, local durability, and configured replicated durability. An append receipt carries information about the appended range and the progress reached. A locally durable write and a write that satisfies a replica acknowledgement policy represent different conditions.&lt;/p&gt;

&lt;p&gt;That distinction helps explain why “the send returned” is too vague for a durability discussion. You need the returned status, acknowledgement policy, topology, and failure scenario. A single-Broker tutorial cannot demonstrate replica failover, and a derived index catching up cannot strengthen an earlier write acknowledgement. See the &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-website/docs/architecture/storage.md" rel="noopener noreferrer"&gt;tagged storage design&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For an evaluation, turn requirements into observable tests. If the service must tolerate a Broker process restart, record sent event identifiers, restart the process under a defined procedure, and reconcile what consumers can recover. A host or disk failure requires a different experiment. Define the expected loss and replay behavior before running either test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why explicit Rust runtime ownership matters
&lt;/h2&gt;

&lt;p&gt;Async messaging software contains work that outlives an individual call: route refreshes, retries, heartbeats, storage activity, and connection cleanup. A library that silently creates executors or leaves detached tasks behind makes lifecycle reasoning harder.&lt;/p&gt;

&lt;p&gt;RocketMQ-Rust's &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-runtime/README.md" rel="noopener noreferrer"&gt;runtime design&lt;/a&gt; gives entry points ownership through RuntimeOwner and passes runtime capabilities into components. The design includes tracked tasks, cancellation, deadlines, bounded blocking work, resource reservations, and shutdown diagnostics. The client receives an explicit shared ClientRuntime rather than relying on a hidden Tokio runtime.&lt;/p&gt;

&lt;p&gt;This creates concrete review questions. Who owns this task? Which budget permits another operation? What cancels it? What evidence remains if shutdown cannot finish? Rust's type and ownership tools can help express those relationships, but the developer still needs to define correct boundaries.&lt;/p&gt;

&lt;p&gt;The 0.9-to-1.0 transition includes source API changes, including fallible client runtime startup and explicit ownership and scheduling APIs. Read the &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-doc/en/release/1.0/api-migration.md" rel="noopener noreferrer"&gt;API migration guide&lt;/a&gt; before adapting older examples.&lt;/p&gt;

&lt;p&gt;A Rust implementation alone establishes no throughput advantage over a Java implementation. Useful comparisons need equivalent durability, replication, payloads, batching, hardware, and failure conditions. Measure latency distributions, memory use, and recovery behavior alongside throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  A reproducible first experiment
&lt;/h2&gt;

&lt;p&gt;Start with the tagged source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/mxsm/rocketmq-rust.git
&lt;span class="nb"&gt;cd &lt;/span&gt;rocketmq-rust
git checkout v1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use the matching &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-website/docs/getting-started/installation.md" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;, &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-website/docs/getting-started/local-source.md" rel="noopener noreferrer"&gt;local cluster guide&lt;/a&gt;, and &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-website/docs/getting-started/quick-start.md" rel="noopener noreferrer"&gt;first-message tutorial&lt;/a&gt;. These commands select the source version; building and running require the prerequisites and configuration in those guides.&lt;/p&gt;

&lt;p&gt;The local setup uses checked-in NameServer and Broker configurations. Its development-insecure-loopback security profile is for the dedicated local tutorial. Do not carry that setting into a shared network or production deployment.&lt;/p&gt;

&lt;p&gt;The tutorial explicitly creates a topic and consumer group, then uses a matched LitePull consumer and producer to exchange five messages. Starting the consumer first makes the bounded demonstration easier to observe. Check the advertised Broker address as well as the NameServer address, because clients must reach both relevant endpoints.&lt;/p&gt;

&lt;p&gt;Pay particular attention to the progress output. The tutorial's OFFSET_COMMIT_REQUESTED marker reports that the commit call returned; it is not a durable Broker acknowledgement. Current LitePull updates client offset-store state separately from persistence. Replace the demonstration's printing step with successful application work and decide how partial-batch failure should affect progress.&lt;/p&gt;

&lt;p&gt;For a second experiment, keep the group and restart the consumer. Then introduce a controlled processing failure. Write down whether work repeats, what progress survives, and which logs explain the result. These exercises teach more than a single successful send.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatibility needs a precise target
&lt;/h2&gt;

&lt;p&gt;Interoperability is easiest to discuss as a specific pairing: a client and Broker version, a protocol path, or a replication mode. “Compatible with RocketMQ” is too broad to decide a deployment.&lt;/p&gt;

&lt;p&gt;The Rust Controller uses OpenRaft for its own consensus implementation. Broker-facing behavior does not make it a peer in a Java JRaft or DLedger consensus group. The 1.0 &lt;a href="https://github.com/mxsm/rocketmq-rust/blob/v1.0.0/rocketmq-doc/en/release/1.0/upgrade-and-rollback.md" rel="noopener noreferrer"&gt;upgrade and rollback guide&lt;/a&gt; also rules out mixed Java/Rust Controller quorums and Java AutoSwitchHA peers. It describes only a bounded Java interoperability profile for DefaultHA.&lt;/p&gt;

&lt;p&gt;Do not assume an existing Java Broker data directory can be handed directly to a Rust Broker. Persisted formats, runtime configuration, wire behavior, and consumer semantics are separate compatibility questions. For upgrades between Rust versions, retain backups and follow the documented downgrade preflight and rollback procedure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluate the workload you actually have
&lt;/h2&gt;

&lt;p&gt;Before a deployment decision, assemble a small evidence checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Message semantics: Which topics require ordering? How are duplicates recognized? What happens when processing fails halfway through a batch?&lt;/li&gt;
&lt;li&gt;Persistence and recovery: Which acknowledgement condition is required? What survives each defined failure? Can you restore and verify retained data?&lt;/li&gt;
&lt;li&gt;Capacity: What happens when consumers slow down? Measure queue growth, memory, disk pressure, and tail latency with realistic payloads.&lt;/li&gt;
&lt;li&gt;Security: Verify identities, credentials, TLS choices, authorization, and the boundary between read-only diagnosis and administrative mutation.&lt;/li&gt;
&lt;li&gt;Operations: Can an operator explain a missing route, rejected write, stalled consumer, or incomplete shutdown using bounded diagnostics?&lt;/li&gt;
&lt;li&gt;Compatibility: Record exact component versions, enabled features, topology, and the tested upgrade and rollback paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treat this list as an experiment plan. A successful build proves that a particular configuration compiles. It does not establish the behavior of every feature, backend, or failure path in the repository. The project's &lt;a href="https://rocketmqrust.com/docs/overview/capability-matrix" rel="noopener noreferrer"&gt;capability matrix&lt;/a&gt; helps identify which boundaries need closer reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the website as a guided code map
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://rocketmqrust.com/docs/getting-started/quick-start" rel="noopener noreferrer"&gt;RocketMQ-Rust documentation&lt;/a&gt; gives readers several routes through the project. Start with the local tutorial to see the complete application path. Move to architecture and message lifecycle to understand what happened. Follow storage, runtime, and protocol boundaries when the implementation becomes relevant.&lt;/p&gt;

&lt;p&gt;For contributors, a narrow, reproducible finding is a useful starting point: a stale example, a shutdown edge case, an unclear error, or a missing regression test. Include the version, configuration, reproduction steps, and expected versus observed behavior. Remove credentials and message payloads from diagnostic material before sharing it.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/mxsm/rocketmq-rust" rel="noopener noreferrer"&gt;repository&lt;/a&gt;, &lt;a href="https://github.com/mxsm/rocketmq-rust/issues" rel="noopener noreferrer"&gt;issue tracker&lt;/a&gt;, and &lt;a href="https://github.com/mxsm/rocketmq-rust/discussions" rel="noopener noreferrer"&gt;discussions&lt;/a&gt; provide places to inspect ongoing work and compare findings. A documentation correction or failure-case test can improve the project's usability as directly as a new feature.&lt;/p&gt;

&lt;p&gt;RocketMQ-Rust is worth examining as a concrete implementation of a difficult systems problem. Follow one message, identify who owns each stage, and test the boundaries your application relies on. That approach produces a grounded decision about where the project fits, and a much clearer understanding of distributed messaging along the way.&lt;/p&gt;

&lt;p&gt;AI disclosure: This draft was generated by AI using the linked project documentation and release sources. It does not report firsthand deployment experience or benchmark results.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
