<?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: Cleiton Augusto </title>
    <description>The latest articles on DEV Community by Cleiton Augusto  (@cleiton_augusto_).</description>
    <link>https://dev.to/cleiton_augusto_</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%2F3547488%2Ffea3af52-a724-429f-af20-3a2121bd4a27.jpg</url>
      <title>DEV Community: Cleiton Augusto </title>
      <link>https://dev.to/cleiton_augusto_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cleiton_augusto_"/>
    <language>en</language>
    <item>
      <title>Nonce Design for Safety-Critical Systems: Lessons from a Post-Quantum MAVLink Protocol</title>
      <dc:creator>Cleiton Augusto </dc:creator>
      <pubDate>Tue, 23 Jun 2026 02:39:57 +0000</pubDate>
      <link>https://dev.to/cleiton_augusto_/nonce-design-for-safety-critical-systems-lessons-from-a-post-quantum-mavlink-protocol-2kmc</link>
      <guid>https://dev.to/cleiton_augusto_/nonce-design-for-safety-critical-systems-lessons-from-a-post-quantum-mavlink-protocol-2kmc</guid>
      <description>&lt;p&gt;Replay attacks on drone command links are not theoretical. A ground station sends &lt;code&gt;ARM&lt;/code&gt; at timestamp T. An adversary records the packet. Thirty seconds later they retransmit it verbatim. If the drone accepts it, you have a serious problem — and in a jammed or contested environment, the attacker can do this silently.&lt;/p&gt;

&lt;p&gt;The standard defense is a monotonically increasing nonce: every packet carries a counter, and the receiver only accepts packets with counters strictly greater than the last accepted value. Simple in concept. The implementation details are where things get interesting.&lt;/p&gt;

&lt;p&gt;This post walks through the nonce design in &lt;a href="https://github.com/cleitonaugusto/CleitonQ" rel="noopener noreferrer"&gt;CleitonQ&lt;/a&gt;, a post-quantum authentication layer for MAVLink v2, and the three decisions that are non-obvious but matter for security.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Concurrent Control Loops
&lt;/h2&gt;

&lt;p&gt;A drone's onboard software runs several concurrent threads: a 100 Hz telemetry loop, a command processor, and potentially a mesh relay. All of them sign outbound packets. All of them need nonces.&lt;/p&gt;

&lt;p&gt;The naive implementation is a shared &lt;code&gt;u64&lt;/code&gt; behind a &lt;code&gt;Mutex&lt;/code&gt;. It works. It's also a footgun: if two threads call &lt;code&gt;next_nonce()&lt;/code&gt; simultaneously without proper synchronization, they can read the same value, both increment to the same next value, and emit duplicate nonces. The receiver sees the duplicate and treats it as a replay — silently dropping a legitimate command.&lt;/p&gt;

&lt;p&gt;In a flight-critical system, a dropped command is not an acceptable error mode.&lt;/p&gt;

&lt;p&gt;The second naive implementation is &lt;code&gt;fetch_add&lt;/code&gt; on an &lt;code&gt;AtomicU64&lt;/code&gt;:&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="c1"&gt;// Tempting, but has a subtle problem&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&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;u64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&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;This fixes the race. But it wraps silently at &lt;code&gt;u64::MAX&lt;/code&gt;. After 18.4 quintillion packets — unlikely in practice, but not impossible over the lifetime of a long-running system — nonce 0 becomes valid again. An adversary who stored a packet from the beginning of time can now replay it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision 1: Saturate, Don't Wrap
&lt;/h2&gt;

&lt;p&gt;CleitonQ's &lt;code&gt;AtomicNonce::next()&lt;/code&gt; uses a compare-and-exchange loop that saturates at &lt;code&gt;u64::MAX&lt;/code&gt; instead of wrapping:&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;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&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;u64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// channel is exhausted, not rolled over&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.compare_exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Relaxed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&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="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&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;When the counter saturates, the receiver rejects &lt;code&gt;u64::MAX&lt;/code&gt; as a replay (it was already accepted). The channel stops working. That is the correct behavior: a locked channel surfaces as an observable failure — an operator sees it, investigates, and re-establishes the session. A silently rolled-over channel surfaces as an intermittent security hole that nobody notices until it's too late.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fail loudly rather than fail silently.&lt;/strong&gt; In safety-critical systems, this principle is not optional.&lt;/p&gt;

&lt;p&gt;The CAS loop also handles the race correctly: if two threads read the same &lt;code&gt;current&lt;/code&gt;, one wins the exchange and the other retries with the updated value. No duplicates, no locks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision 2: Memory Ordering Is Not Symmetric
&lt;/h2&gt;

&lt;p&gt;The sender (&lt;code&gt;AtomicNonce&lt;/code&gt;) and the receiver (&lt;code&gt;NonceTracker&lt;/code&gt;) have different memory ordering requirements, and they are not interchangeable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AtomicNonce::next()&lt;/code&gt; uses &lt;code&gt;Relaxed&lt;/code&gt; for both the load and the CAS. This is intentional. The only property needed is that each call returns a unique, strictly increasing value. There is no requirement that the nonce emission &lt;em&gt;happens-before&lt;/em&gt; anything else in the caller's memory. The packet containing the nonce will be serialized and sent over the network — the network ordering establishes the happens-before relationship with the receiver. Using &lt;code&gt;SeqCst&lt;/code&gt; here would be correct but unnecessary, adding synchronization overhead on every outbound packet in a 100 Hz loop.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;NonceTracker::accept()&lt;/code&gt; is different:&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;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&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;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Acquire&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.compare_exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AcqRel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Acquire&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&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="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&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;The receiver uses &lt;code&gt;Acquire&lt;/code&gt; on the load and &lt;code&gt;AcqRel&lt;/code&gt; on the successful exchange. This establishes a happens-before edge: any thread that subsequently reads the tracker's value with &lt;code&gt;Acquire&lt;/code&gt; sees all writes that preceded the accepted nonce. In practice this means: the authentication check that accepted a packet happens-before any processing of that packet's payload. If two threads race to accept the same nonce, exactly one wins the CAS — the other sees &lt;code&gt;nonce &amp;lt;= current&lt;/code&gt; on retry and returns &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;Relaxed&lt;/code&gt; on the receiver would be wrong. It would allow a theoretical reordering where a thread begins processing a payload before the nonce check completes — which, in a language with a memory model that permits this, is a real vulnerability class.&lt;/p&gt;




&lt;h2&gt;
  
  
  Decision 3: Process Restarts Without Persistent State
&lt;/h2&gt;

&lt;p&gt;What happens when the companion computer reboots mid-flight? The &lt;code&gt;AtomicU64&lt;/code&gt; in RAM is gone. If the new process starts from 0, every nonce it emits is below the receiver's &lt;code&gt;last_accepted&lt;/code&gt; — the channel is dead until a new session is established.&lt;/p&gt;

&lt;p&gt;One answer is NVRAM persistence: write the nonce to flash periodically, read it on boot. This works but adds I/O latency on the critical path and creates a new failure mode: flash write corruption during power loss.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AtomicNonce::from_time()&lt;/code&gt; takes a different approach:&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;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&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;nanos&lt;/span&gt; &lt;span class="o"&gt;=&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;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;SystemTime&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.duration_since&lt;/span&gt;&lt;span class="p"&gt;(&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;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UNIX_EPOCH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap_or_default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.as_nanos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nanos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MAX&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;Seeding from nanoseconds since the Unix epoch means a restarted process almost certainly starts with nonces higher than anything emitted before the restart. A 10-second reboot adds 10 billion nonces of headroom. A 1-millisecond glitch adds 1 million. The wall clock is the implicit persistent store.&lt;/p&gt;

&lt;p&gt;This relies on the system clock being monotonic across reboots — which is true on any platform with a battery-backed RTC and NTP. On systems without one (some deeply embedded targets), &lt;code&gt;from_time()&lt;/code&gt; is unavailable and the application must manage initial nonce values explicitly.&lt;/p&gt;

&lt;p&gt;The deeper architectural answer is that CleitonQ's session boundary makes this largely moot: a reboot forces a new ML-KEM session, which establishes a new session key. Since nonces are checked within a session (HMAC tags include the session key), cross-session replay is impossible regardless of nonce values.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Embedded Target
&lt;/h2&gt;

&lt;p&gt;Not all targets have 64-bit atomics. Cortex-M4 (the processor in most Pixhawk flight controllers) does not. For these, CleitonQ provides &lt;code&gt;SimpleNonce&lt;/code&gt; and &lt;code&gt;SimpleNonceTracker&lt;/code&gt;:&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;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;SimpleNonce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;SimpleNonce&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;next_nonce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&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;u64&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;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.wrapping_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;v&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;These are not thread-safe — the &lt;code&gt;&amp;amp;mut self&lt;/code&gt; receiver makes that explicit at the type level. On a single-threaded embedded executor, this is correct and zero-overhead. On a multi-threaded target with 64-bit atomics, the compiler will refuse to compile the single-threaded variant in a shared context.&lt;/p&gt;

&lt;p&gt;The platform split is expressed via &lt;code&gt;#[cfg(target_has_atomic = "64")]&lt;/code&gt;, not runtime checks — it's a compile-time guarantee, not a runtime assertion.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing the Properties
&lt;/h2&gt;

&lt;p&gt;Three properties need tests, not documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uniqueness under concurrency&lt;/strong&gt; — 8 threads each calling &lt;code&gt;next()&lt;/code&gt; 1000 times should produce 8000 distinct nonces:&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;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;AtomicNonce&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&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;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&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="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HashSet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nonce&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&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;all&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"duplicate nonce — race in AtomicNonce::next"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Replay rejection&lt;/strong&gt; — the tracker must reject exact replays and regressions:&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;let&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;NonceTracker&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&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;t&lt;/span&gt;&lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&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="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// exact replay&lt;/span&gt;
&lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// regression&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;t&lt;/span&gt;&lt;span class="nf"&gt;.accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;    &lt;span class="c1"&gt;// forward progress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;No double-accept under concurrency&lt;/strong&gt; — 4 threads racing to accept nonces 1..=500 should produce exactly 500 total acceptances:&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;let&lt;/span&gt; &lt;span class="n"&gt;tracker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;NonceTracker&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// 4 threads, each tries to accept all 500 nonces&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;total_accepted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_accepted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tracker&lt;/span&gt;&lt;span class="nf"&gt;.last_accepted&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These tests run on every CI push, including on a Neoverse-N2 ARM64 runner that mirrors the hardware profile of production companion computers.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Broader Point
&lt;/h2&gt;

&lt;p&gt;Nonce design looks simple until you consider the combination of concurrent writers, concurrent readers, process restarts, and an adversary who stores packets indefinitely. Each of those constraints pushes the design in a different direction. Getting all four right simultaneously requires explicit reasoning about each decision — not just picking the first implementation that passes the unit tests.&lt;/p&gt;

&lt;p&gt;The three decisions above — saturating arithmetic, asymmetric memory ordering, and clock-seeded initialization — are each defensible in isolation. Together they form a design that fails loudly, maintains happens-before guarantees where they matter, and survives the most common production failure mode (process restart) without persistent state.&lt;/p&gt;

&lt;p&gt;CleitonQ is open source under MIT OR Apache-2.0. The full nonce implementation, with all tests, is in &lt;a href="https://github.com/cleitonaugusto/CleitonQ/blob/main/src/nonce.rs" rel="noopener noreferrer"&gt;&lt;code&gt;src/nonce.rs&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;CleitonQ is a post-quantum authentication layer for MAVLink v2, combining ML-KEM-1024 (FIPS 203) for session establishment and ML-DSA-87 (FIPS 204) for command signing. A formal security model in ProVerif 2.05 verifies session key secrecy (Q1) and command authenticity (Q2) against a Dolev-Yao attacker. &lt;a href="https://doi.org/10.5281/zenodo.20776349" rel="noopener noreferrer"&gt;Paper on Zenodo&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>security</category>
      <category>embedded</category>
      <category>drone</category>
    </item>
    <item>
      <title>Implementing Adaptive Backpressure in Rust with FlowGuard</title>
      <dc:creator>Cleiton Augusto </dc:creator>
      <pubDate>Sat, 27 Dec 2025 15:43:34 +0000</pubDate>
      <link>https://dev.to/cleiton_augusto_/implementing-adaptive-backpressure-in-rust-with-flowguard-1iof</link>
      <guid>https://dev.to/cleiton_augusto_/implementing-adaptive-backpressure-in-rust-with-flowguard-1iof</guid>
      <description>&lt;p&gt;Implementing Adaptive Backpressure in Rust with FlowGuard&lt;br&gt;
Hey fellow Rustaceans! 👋&lt;/p&gt;

&lt;p&gt;I recently open-sourced FlowGuard, a library for adaptive concurrency control and backpressure in Rust services. In this post, I'll share why static rate limiting fails and how FlowGuard solves it with TCP Vegas congestion control.&lt;/p&gt;

&lt;p&gt;🤔 The Problem with Static Limits&lt;br&gt;
We've all done this:&lt;/p&gt;

&lt;p&gt;rust&lt;br&gt;
// "Maximum 100 concurrent connections"&lt;br&gt;
let max_connections = 100;&lt;br&gt;
But static limits are a trap:&lt;/p&gt;

&lt;p&gt;Set too high? Your system crashes before reaching the limit&lt;/p&gt;

&lt;p&gt;Set too low? You waste resources and refuse legitimate traffic&lt;/p&gt;

&lt;p&gt;Guessing game? You're always tuning based on hunches&lt;/p&gt;

&lt;p&gt;🚀 The Solution: Dynamic Backpressure&lt;br&gt;
Instead of guessing, what if your system could self-adjust based on real-time performance? That's where FlowGuard comes in.&lt;/p&gt;

&lt;p&gt;Introducing FlowGuard&lt;br&gt;
FlowGuard implements the TCP Vegas congestion control algorithm to dynamically adjust concurrency limits based on actual system latency.&lt;/p&gt;

&lt;p&gt;🎯 How It Works&lt;br&gt;
rust&lt;br&gt;
use flow_guard::{FlowGuard, VegasStrategy};&lt;br&gt;
use std::sync::Arc;&lt;/p&gt;

&lt;h1&gt;
  
  
  [tokio::main]
&lt;/h1&gt;

&lt;p&gt;async fn main() {&lt;br&gt;
    // Start with 10 concurrent operations&lt;br&gt;
    let strategy = Arc::new(VegasStrategy::new(10));&lt;br&gt;
    let guard = FlowGuard::new(Arc::clone(&amp;amp;strategy));&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;println!("Initial limit: {}", guard.current_limit());

// Execute tasks with adaptive backpressure
let result = guard.run(async {
    // Your database query, API call, etc.
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    Ok::&amp;lt;_, &amp;amp;str&amp;gt;("Success!")
}).await;

println!("Final limit: {}", guard.current_limit()); // Adjusted!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
✨ Key Features&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Real-time Adjustment
rust
// Watch limits adjust dynamically
println!("Current limit: {}", guard.current_limit());
println!("Available permits: {}", guard.available_permits());&lt;/li&gt;
&lt;li&gt;Vegas Algorithm
Based on the difference between expected and actual throughput:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;✅ Increases limit when system has spare capacity&lt;/p&gt;

&lt;p&gt;✅ Decreases limit when latency indicates congestion&lt;/p&gt;

&lt;p&gt;✅ Self-tuning - no manual configuration needed&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Web Framework Integration
rust
// Axum 0.8 middleware
let strategy = VegasStrategy::new(50);
let flow_layer = FlowGuardLayer::new(strategy);&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;let app = Router::new()&lt;br&gt;
    .route("/api/data", get(handler))&lt;br&gt;
    .layer(flow_layer);&lt;br&gt;
📦 Getting Started&lt;br&gt;
Add to your Cargo.toml:&lt;/p&gt;

&lt;p&gt;toml&lt;br&gt;
[dependencies]&lt;br&gt;
flow-guard = "0.2.1"&lt;/p&gt;

&lt;h1&gt;
  
  
  With Axum/Tower support
&lt;/h1&gt;

&lt;p&gt;flow-guard = { version = "0.2.1", features = ["axum", "tower"] }&lt;br&gt;
🔧 Under the Hood&lt;br&gt;
FlowGuard replaces tokio::sync::Semaphore with a custom DynamicSemaphore that can adjust its limit up and down in real-time:&lt;/p&gt;

&lt;p&gt;rust&lt;br&gt;
pub struct DynamicSemaphore {&lt;br&gt;
    max_permits: AtomicUsize,&lt;br&gt;
    available_permits: AtomicUsize,&lt;br&gt;
    notify: Notify,&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;impl DynamicSemaphore {&lt;br&gt;
    pub fn set_limit(&amp;amp;self, new_limit: usize) {&lt;br&gt;
        // Adjusts permits dynamically based on Vegas calculations&lt;br&gt;
    }&lt;br&gt;
}&lt;br&gt;
🎯 Use Cases&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Database Protection
rust
// Prevent database overload
let db_guard = FlowGuard::new(VegasStrategy::new(20));&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;async fn query_database() -&amp;gt; Result {&lt;br&gt;
    db_guard.run(|| async {&lt;br&gt;
        // Your database query here&lt;br&gt;
        database.query("SELECT * FROM users").await&lt;br&gt;
    }).await``&lt;br&gt;
}&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;API Rate Limiting
rust
// Adaptive rate limiting for external APIs
let api_guard = FlowGuard::new(VegasStrategy::new(5));&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;async fn call_external_api() -&amp;gt; Result {&lt;br&gt;
    api_guard.run(|| async {&lt;br&gt;
        client.get("&lt;a href="https://api.example.com/data%22).await" rel="noopener noreferrer"&gt;https://api.example.com/data").await&lt;/a&gt;&lt;br&gt;
    }).await&lt;br&gt;
}&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Microservices
rust
// Protect services from cascading failures
let service_guard = FlowGuard::new(VegasStrategy::new(100));
📊 Benchmarks
In testing, FlowGuard showed:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;5 → 12 limit adjustment under optimal conditions&lt;/p&gt;

&lt;p&gt;Sub-millisecond overhead per request&lt;/p&gt;

&lt;p&gt;Zero allocation in hot path&lt;/p&gt;

&lt;p&gt;Thread-safe with atomic operations&lt;/p&gt;

&lt;p&gt;🚀 Try It Yourself&lt;br&gt;
bash&lt;/p&gt;

&lt;h1&gt;
  
  
  Clone and run examples
&lt;/h1&gt;

&lt;p&gt;git clone &lt;a href="https://github.com/cleitonaugusto/flow-guard" rel="noopener noreferrer"&gt;https://github.com/cleitonaugusto/flow-guard&lt;/a&gt;&lt;br&gt;
cd flow-guard&lt;br&gt;
cargo run --example basic_usage&lt;br&gt;
🔗 Resources&lt;br&gt;
GitHub: &lt;a href="https://github.com/cleitonaugusto/flow-guard" rel="noopener noreferrer"&gt;https://github.com/cleitonaugusto/flow-guard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Crates.io: &lt;a href="https://crates.io/crates/flow-guard" rel="noopener noreferrer"&gt;https://crates.io/crates/flow-guard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Documentation: &lt;a href="https://docs.rs/flow-guard/0.2.1/" rel="noopener noreferrer"&gt;https://docs.rs/flow-guard/0.2.1/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Examples: basic_usage.rs, server_demo.rs&lt;/p&gt;

&lt;p&gt;💭 Why I Built This&lt;br&gt;
After seeing too many services crash from static limits or waste resources with conservative settings, I wanted a solution that adapts to actual system performance. The TCP Vegas algorithm has been battle-tested for decades in networking - why not apply it to service concurrency?&lt;/p&gt;

&lt;p&gt;🤝 Contributing &amp;amp; Feedback&lt;br&gt;
FlowGuard is open source under MIT license. I'd love your:&lt;/p&gt;

&lt;p&gt;Feedback on the API design&lt;/p&gt;

&lt;p&gt;Use cases from your projects&lt;/p&gt;

&lt;p&gt;Contributions to the codebase&lt;/p&gt;

&lt;p&gt;Ideas for improvements&lt;/p&gt;

&lt;p&gt;What adaptive concurrency patterns have you used in your Rust projects? Share in the comments!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>rust</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
