Expand description
Multiprocess shared-memory transport for inference and other low-latency pipelines.
myelon is the full transport surface built on top of
disruptor_mp.
The design goal is straightforward:
- the raw ring should remain reachable
- the higher layers should be available when you need them
- callers should not have to assemble framing, typed transport, and zero-copy access as separate dependencies
myelon therefore re-exports the raw substrate from
disruptor_mp and adds framed transport, codec-backed typed
transport, typed zero-copy, topology helpers, and transport-layout
helpers behind one dependency.
Both myelon and disruptor-mp are valid entry points. Use
myelon when you want the higher-level transport layers available;
use disruptor-mp directly when you only need the raw substrate.
Type identity is preserved across the re-export boundary, so a
disruptor_mp::SharedConsumer<E> is the same type as a
myelon::SharedConsumer<E>.
§What this crate exposes
| Need | Layer | Type |
|---|---|---|
Fixed-size, Copy event. You own the wire format. | 0 — raw | SharedProducer<E> / SharedConsumer<E> (SHM) or MmapProducer<E> / MmapConsumer<E> (mmap) |
Variable-length &[u8] payloads, possibly larger than one ring slot. Need start/end flags + a message id. | 1 — framed | transport::FramedTransportProducer / transport::FramedTransportConsumer (SHM) or transport::MmapFramedTransportProducer / transport::MmapFramedTransportConsumer (mmap) |
| Typed message with serialisation (bincode / rkyv / flatbuffers). Owned decode on the consumer side. | 2 — codec | typed_transport::TypedProducer / typed_transport::TypedConsumer + a codec::Codec impl |
Same as Layer 2 but consumer reads serialised data in-place — no deserialize allocation. | 3 — typed zero-copy | typed_transport::TypedProducer / typed_transport::TypedConsumer + a codec::ZeroCopyCodec impl |
Pick the highest-level surface that matches your data model, then measure before stepping down.
§Choosing a frame size
The framed transport’s frame type is a const generic — callers pick the per-frame payload capacity at compile time:
use myelon::transport::{FixedFrame, AlignedFixedFrame};
type Frame64K = FixedFrame<{ 64 * 1024 - 12 }>; // 12-byte header
type FrameTiny = FixedFrame<256>;
type Frame4K = FixedFrame<{ 4 * 1024 - 12 }>;
type ZcFrame = AlignedFixedFrame<{ 64 * 1024 - 16 }>; // 16-byte headerThere is nothing special about 64 KB — that is just the convention
perf-bench
uses. The trade-off:
| Frame size | Effect |
|---|---|
Larger DATA_BYTES | Bigger ring slot, bigger SHM footprint for the same depth, but messages that fit in one slot avoid fragmentation. |
Smaller DATA_BYTES | Smaller slot, tighter memory, multi-frame fragmentation kicks in once payload exceeds DATA_BYTES. |
| Right-sized to dominant payload | Single-frame messages, lowest overhead, at the cost of flexibility for atypical sizes. |
The slot size must be a compile-time constant so the ring layout
is known. To support a runtime-chosen size, instantiate one
transport per size class. perf-bench’s nofrag mode is a
worked example of this pattern.
§Two senses of zero-copy
Two different things in this stack get called “zero-copy”, and they’re not the same:
| Sense | Where | How |
|---|---|---|
| Memory-level zero-copy | Layer 0 already provides this. | try_consume_next_leased() returns &E straight into the ring slot. No allocation, no copy. Use this for fixed-size Copy + repr(C) events. |
| Typed-format zero-copy | Layer 3. | The bytes on the wire are already a serialised graph (rkyv Archived<T> or a flatbuffers root table); the consumer reads fields in-place via codec::ZeroCopyCodec::access. |
There is no separate “raw + typed zero-copy” layer. If your event
is fixed-size and Copy + repr(C), just put the struct in the
slot — Layer 0 is already memory-zero-copy and outperforms an
archived blob. If you want serialisation flexibility, you also
want framing. The four-layer picture covers both senses without
overlap.
§Cross-cutting concerns
These wrap across layers — pick them by what your system needs, not by what your wire format needs.
| Concern | Type | Purpose |
|---|---|---|
| Coordination | producer::CoordinationMode | When does the producer consider its peers attached? |
| Discovery | builder methods on SharedDisruptorBuilder | Producer locates consumers by explicit ID or by prefix. |
| Liveness | RequiredConsumerLivenessConfig, RequiredConsumerFailureAction (see below) | A stalled required consumer becomes a failure or alert, not silent backpressure. |
| Topology | inference::FixedTopology, inference::WorkerCount | Pre-baked one-scheduler / N-worker shape with discovery + rendezvous. |
| Layout | transport::MyelonTransportLayout, transport::MyelonTransportConfig, transport::RunnerMyelonTransportConfig | macOS-safe SHM segment names for one-engine / N-runner sessions. |
| Observability | observability (re-export of disruptor_mp::observability) | RFC-0040 hot-path counters file. |
§Required-consumer liveness
Out of the box, the base model is strict broadcast — the slowest consumer gates capacity. A stalled or crashed required consumer therefore backpressures the producer indefinitely. The optional liveness layer turns that silent stall into a producer-observable, time-bounded event.
It is opt-in through a parallel *_managed publish surface.
Existing unmanaged calls (publish, try_publish, publish_batch)
keep their original semantics; nothing changes for callers that
don’t opt in.
Available on every layer:
| Layer / backend | Type | Methods |
|---|---|---|
| 0, SHM | SharedProducer<E> | enable_required_consumer_liveness, publish_managed, publish_batch_managed |
| 0, mmap | MmapProducer<E> | same |
| 1, SHM | transport::FramedTransportProducer | enable_required_consumer_liveness, publish_managed |
| 1, mmap | transport::MmapFramedTransportProducer | same |
| 2/3, SHM | typed_transport::TypedProducer | enable_required_consumer_liveness, publish_managed |
| 2/3, mmap | typed_transport::MmapTypedProducer | same |
Failure surface (returned from publish_managed):
| Case | Outcome |
|---|---|
Required consumer doesn’t appear within startup_wait_timeout. | RequiredConsumerError::StartupTimeout |
Required consumer stalls past progress_timeout while gating the producer. | One stderr alert + optional RequiredConsumerAlertHook callback. |
Same consumer ID rejoins before shutdown_grace_period expires. | Producer recovers, alert state clears, publishing resumes. |
Stall persists past shutdown_grace_period. | RequiredConsumerError::GracefulShutdownTriggered |
The liveness check is cold-path only — it runs only while the producer is blocked on a gating required consumer. Steady-state publish cost is unchanged. There is no consumer-side heartbeat; progress is observed from the cursor data the producer already needs for gating.
By design the liveness layer does not add dead-consumer eviction, quorum modes, or degraded broadcast. The topology stays strict-broadcast.
§Feature flags
| Feature | Layer / surface | What it enables |
|---|---|---|
| (default) | Layers 0, 1; Layer 2 with bincode only | Raw + framed transport, plus the bincode codec. |
rkyv | Layer 2/3 with rkyv | Re-exports rkyv and the rkyv codec wrappers (incl. codec::ZeroCopyCodec). |
flatbuffers | Layer 2/3 with flatbuffers | Re-exports flatbuffers and the flatbuffers codec wrappers. |
dst | tests only | Forwards to disruptor_mp/dst for deterministic-simulation hooks. |
§Quick start
use myelon::{
attach_shared_consumer, build_shared_single_producer,
};
use myelon::producer::CoordinationMode;
use disruptor_mp::portable_shm_segment_name;
let segment = portable_shm_segment_name("demo");
let mut producer = build_shared_single_producer::<Event>(&segment, 4096)
.discover_consumer_with_prefix(1, "cp")
.with_coordination(CoordinationMode::Immediate)
.build_producer(Event::default)
.expect("build producer");
producer.publish(|slot| slot.sequence = 1);See the crate README for fuller Layer 1 / Layer 2 / Layer 3 examples.
Re-exports§
pub use inference::FixedTopology;pub use inference::InferenceTopologyError;pub use inference::InferenceTopologyResult;pub use inference::WorkerCount;pub use transport::compact_session_tag;pub use transport::coordination_cursor_name;pub use transport::ensure_coordination_cursor;pub use transport::frame_flags;pub use transport::is_last_frame;pub use transport::is_single_frame;pub use transport::publish_framed_payload;pub use transport::recv_framed_message;pub use transport::validate_segment_name;pub use transport::AlignedFixedFrame;pub use transport::FrameMeta;pub use transport::MmapFramedTransportConsumer;pub use transport::MmapFramedTransportProducer;pub use transport::MyelonTransportConfig;pub use transport::MyelonTransportLayout;pub use transport::MyelonWaitStrategy;pub use transport::RunnerMyelonTransportConfig;pub use transport::TransportError;pub use transport::TransportResult;pub use transport::DEFAULT_MYELON_RESPONSE_DEPTH;pub use transport::DEFAULT_MYELON_RPC_DEPTH;pub use transport::DEFAULT_TRANSPORT_PREFIX;pub use transport::SEGMENT_NAME_LIMIT_MACOS;pub use codec::Codec;pub use codec::CodecError;pub use typed_transport::MmapTypedConsumer;pub use typed_transport::MmapTypedProducer;pub use typed_transport::TypedConsumer;pub use typed_transport::TypedProducer;pub use typed_transport::TypedPublishError;pub use rkyv;pub use flatbuffers;
Modules§
- backend
- Backend façade namespace for shared-memory implementation.
- codec
- Zero-copy message codec for the Myelon transport.
- consumer
- Consumer façade namespace for shared-memory consumer behavior.
- inference
- Fixed-topology inference helpers over the curated
disruptor-mpfaçade. - lock_
free - Lock-free coordination façade types.
- observability
- Re-export of
disruptor_mp::observabilityfor downstream users that want to attach Aeron-style hot-path counters without taking a direct dependency ondisruptor-mp. RFC 0040. - prelude
- Convenience re-exports for downstream code that wants the typical
transport, codec, and observability surface in one
useline. - producer
- Producer façade namespace for coordinated construction and policy.
- shared_
memory - Shared-memory top level façade types.
- transport
- Portable transport helpers for inference-fabric integrations.
- typed_
transport - Typed transport wrappers that integrate
Codecwith the rawFramedTransportProducer/FramedTransportConsumer.
Structs§
- Auto
Consumer - Automatic consumer that runs in a background thread.
- Mmap
Consumer - Consumer for the mmap transport.
- Mmap
Producer - Producer for the mmap transport.
- Mmap
Transport Layout - Stable file layout for one mmap-backed disruptor transport instance.
- Required
Consumer Alert - Producer-side alert emitted when a required consumer stops advancing while gating progress.
- Required
Consumer Liveness Config - Producer-side liveness policy for a required consumer set.
- Ring
Buffer Full - Error indicating that the ring buffer is full.
- Shared
Consumer - Consumer for multi-process disruptor with broadcast semantics Each consumer maintains its own sequence and sees all events
- Shared
Disruptor Builder - Builder for creating multi-process disruptors.
- Shared
Producer - Multi-process producer for publishing events to shared memory ring buffer.
Enums§
- Auto
Wait Strategy - Wait strategy for automatic event handlers
- Coordination
Mode - Coordination mode for multiprocess producer startup
- Multi
Process Error - Errors that can occur during multi-process setup
- Required
Consumer Error - Producer-visible failure when required-consumer liveness cannot be maintained.
- Required
Consumer Failure Action - Action to take when a required consumer stops making progress.
Constants§
- DEFAULT_
MAX_ CONSUMERS - Default maximum number of consumers that can be registered with a single shared ring buffer.
- PORTABLE_
SHM_ SEGMENT_ NAME_ MAX_ LEN - Conservative shared-memory segment-name budget that stays portable on macOS.
Functions§
- attach_
shared_ consumer - Attach to an existing shared disruptor as a consumer
- build_
shared_ single_ producer - Create a shared single producer for multi-process communication
- default_
block_ strategy_ duration - Return the configured backoff used by
AutoWaitStrategy::Block. - default_
consume_ sleep_ duration - Return the configured sleep used by
consume_next_with_sleepand similar helpers. - default_
discovery_ poll_ duration - Return the configured poll interval used by discovery/startup coordination loops.
- perform_
default_ block_ wait - Apply the configured
AutoWaitStrategy::Blockwait policy. - perform_
default_ consume_ sleep_ wait - Apply the configured consumer sleep wait policy.
- perform_
default_ discovery_ poll_ wait - Apply the configured discovery/startup polling wait policy.
- perform_
sleep_ wait - Apply the explicit
AutoWaitStrategy::Sleep(duration)wait policy. - portable_
shm_ segment_ name - Generate a shared-memory segment name that fits the portable macOS-safe budget.
Type Aliases§
- Multi
Process Result - Result type for multi-process operations
- Required
Consumer Alert Hook - Optional embedding hook invoked when producer-side stall alerting fires.
- Sequence
- The type for Sequence numbers in the Ring Buffer (
i64).