rusteron-client
rusteron-client is a core component of the Rusteron project.
It provides a Rust wrapper around the Aeron C client API, enabling high-performance, low-latency communication in distributed systems built with Rust.
This crate supports publishing, subscribing, and managing Aeron resources, while exposing a flexible and idiomatic interface over unsafe C bindings.
Due to its reliance on raw FFI, developers must take care to manage resource lifetimes and concurrency correctly.
Sponsored by GSR
Rusteron is proudly sponsored and maintained by GSR, a global leader in algorithmic trading and market making in digital assets.
It powers mission-critical infrastructure in GSR's real-time trading stack and is now developed under the official GSR GitHub organization as part of our commitment to open-source excellence and community collaboration.
We welcome contributions, feedback, and discussions. If you're interested in integrating or contributing, please open an issue or reach out directly.
Features
- Client Setup – Create and start an Aeron client using Rust.
- Publications – Send messages via
offer()ortry_claim(). - Subscriptions – Poll for incoming messages and handle fragments.
- Callbacks & Handlers – React to driver events like availability, errors, and stream lifecycle changes.
- Cloneable Wrappers – All client types are cloneable and share ownership of the underlying C resources.
- Automatic Resource Management – Objects created with
.new()automatically call*_initand*_close, where supported. - Result-Focused API – Methods returning primitive C results return
Result<T, AeronCError>for ergonomic error handling. - Efficient String Interop – Inputs use
&CStr, outputs return&str, giving developers precise allocation control.
Installation
Add rusteron-client to your Cargo.toml:
# Dynamic linking (default)
= "0.1"
# Static linking
= { = "0.1", = ["static"] }
# Static linking with precompiled C libraries (best for Mac users, no Java/cmake needed)
= { = "0.1", = ["static", "precompile"] }
# Static linking with precompiled C libraries using rustls downloader
= { = "0.1", = ["static", "precompile-rustls"] }
When using the default dynamic configuration, you must ensure Aeron C libraries are available at runtime. The static option embeds them automatically into the binary.
General Patterns
new()Initialization: Automatically calls the corresponding*_initmethod.- Automatic Cleanup (Partial): When possible,
Dropwill invoke the appropriate*_closeor*_destroymethods. - Manual Resource Responsibility: For methods like
set_aeron()or where lifetimes aren't managed internally, users are responsible for safety. - Handlers Must Be Leaked and Released: Callbacks passed to the C layer require explicit memory management using
Handlers::leak(...)andHandlers::release(...).
Handlers and Callbacks
Handlers allow users to customize responses to Aeron events (errors, image availability, etc). There are two ways to use them:
1. Implementing a Trait (Recommended)
This is the most performant and idiomatic approach for long-lived handlers (e.g. an error handler installed on the context).
use *;
;
Wrap it with Handler::leak(...) to pass it into the C layer, and call release() once it's no longer needed:
let handler = leak;
ctx.set_error_handler?;
// ...when done:
handler.release;
2. Short-lived Polls: Closures
For one-off message consumption, skip the trait and pass a closure directly to poll_once — no leak/release bookkeeping needed:
subscription.poll_once?;
For messages larger than the MTU that need reassembling, use a fragment assembler with
subscription.poll(Some(&handler), limit)—poll_oncedelivers raw fragments and does not reassemble.
No handler needed for an optional slot? Use the typed None helpers, e.g. Handlers::no_error_handler_handler().
Minimal Pub/Sub
use *;
use Duration;
let ctx = new?;
// Reuse the built-in logger for async client errors (Aeron samples always set one).
let mut error_handler = leak;
ctx.set_error_handler?;
let aeron = new?;
aeron.start?;
let channel = &"aeron:ipc".into_c_string;
let publication = aeron
.async_add_publication?
.poll_blocking?;
let subscription = aeron
.async_add_subscription?
.poll_blocking?;
// offer() returns the log position (>0) or a negative code — see "Errors & offer results".
while publication.offer <= 0
subscription.poll_once?;
error_handler.release;
Errors & offer results
- Client errors: install an error handler on the context (
ctx.set_error_handler(Some(&handler))) so async errors aren't silently lost — Aeron's samples always do. Leaked handlers must berelease()d. offer()/try_claim()results: a positive value is the resulting log position; the negatives are classified by thePUBLICATION_*constants.PUBLICATION_CLOSED,PUBLICATION_MAX_POSITION_EXCEEDED, andPUBLICATION_ERRORare fatal (stop offering);PUBLICATION_BACK_PRESSURED,PUBLICATION_NOT_CONNECTED, andPUBLICATION_ADMIN_ACTIONare transient (retry, ideally with an idle strategy). This mirrors Aeron'sBasicPublisher.checkResult.let r = publication.offer; if r == PUBLICATION_CLOSED || r == PUBLICATION_MAX_POSITION_EXCEEDED- Image handlers:
Handlers::no_available_image_handler()/no_unavailable_image_handler()are fine as a default, but real apps usually react to image availability (logging, synchronization) — Aeron'sPingsample uses one as a latch.
Idle strategies
Poll loops should back off when a cycle does no work. Rusteron ports Aeron's IdleStrategy
(idle(work_count) returns immediately when work was done, otherwise backs off):
use ;
let mut idle = new; // spin → yield → sleep, Aeron's default
loop
Available: [BusySpinIdleStrategy] (lowest latency, pins a core), [YieldingIdleStrategy],
[SleepingIdleStrategy] (fixed sleep), [BackoffIdleStrategy] (adaptive, general-purpose),
[NoOpIdleStrategy]. Latency benchmarks should keep busy-spin.
For recording, replay, and persistent subscriptions (replay history, then seamlessly join a live stream), see rusteron-archive.
Contributing & License
See the root README and CONTRIBUTING.md. Dual-licensed under MIT or Apache-2.0.
Acknowledgments
Special thanks to:
- @mimran1980, a core low-latency developer at GSR and the original creator of Rusteron - your work made this possible!
- @bspeice for the original
libaeron-sys - The Aeron community for open protocol excellence