Expand description
reliar-core is the pure envelope/message model every Reliar crate builds on: identity
newtypes, the Message contract, a validated Headers map, typed Metadata, and the
Envelope/SerializedEnvelope pair that carries them. It has no storage or transport
dependency of its own — no sqlx, no broker client, no routing concept (a Kafka partition key,
a RabbitMQ exchange, a NATS subject) — so it is useful standalone, as the shared vocabulary
two independent Reliar crates (say an outbox and a transport) use to talk to each other, or as
a typed envelope model for an application that does not use the rest of Reliar at all.
§The types you touch
Message— implement this on your own type to give it a stable, renaming-proof identity (TYPE+VERSION), never derived fromstd::any::type_name::<T>()or a module path.Envelope<T>/SerializedEnvelope— the same generic type on both sides of serialization: anEnvelope<YourType>on the way in,Envelope<bytes::Bytes>once aSerializerhas turned the body to bytes. Build one withEnvelope::builder.Metadata— canonical, typed framework metadata (correlation, trace, routing, delivery, tenant). One source of truth: a value here is never duplicated intoHeaders, and Reliar never reads a framework value back out of headers.Headers— your own custom, application-defined metadata. A validating newtype, not a bare map: it rejects the entirereliar-prefix case-insensitively, so a custom header can never collide with — or be mistaken for — a framework one.Serializer(default impl:JsonSerializer, behind the defaultjsonfeature) — converts a typed body to and from bytes.Publisher— the trait a transport implements to send an envelope; paired withClassify/FailureKindso a caller can tell a retryable failure from a permanent one without inspecting transport internals.
§End to end
JsonSerializer ships behind the default json feature; without it this block still shows
the shape but is not compiled (cargo test --doc --no-default-features would not see
JsonSerializer/JsonError).
use reliar_core::{Envelope, JsonSerializer, Message, Serializer};
#[derive(serde::Serialize, serde::Deserialize)]
struct OrderCreated {
order_id: u64,
}
impl Message for OrderCreated {
const TYPE: &'static str = "orders.created";
const VERSION: u16 = 1;
}
// Build a typed envelope; `message_type` and the conversation root are derived, not chosen.
let envelope = Envelope::builder(OrderCreated { order_id: 42 })
.tenant("acme")
.build();
assert_eq!(envelope.message_type.to_string(), "orders.created.v1");
// Serialize the body; the serialized envelope is what storage/transport crates see.
let serializer = JsonSerializer;
let bytes = serializer.serialize(&envelope.body)?;
let serialized = envelope.map_body(|_| bytes);
assert_eq!(serialized.metadata.tenant_id.as_deref(), Some("acme"));Every public error is a hand-rolled, #[non_exhaustive] enum with a wired
std::error::Error::source — no thiserror, no anyhow. Debug on payload-bearing types
elides the bytes; no Display here ever prints a payload, a header value, or a credential.
Structs§
- Content
Type - A validated MIME type. Owned by the
Serializerthat produced a payload — never chosen at the call site (ADR 0010). - Conversation
Id - Groups every message in one business conversation. Always derived, never minted: an
un-correlated message roots its own conversation at its
MessageId(seecrate::EnvelopeBuilder::build), and any other value is inherited from storage or the wire viaSelf::from_uuid. There is deliberately nonew()/Default— a random, unrooted conversation id would silently drop a caller out of the conversation it supplied (ADR 0038); a host that wants to start one names the UUID explicitly. - Correlation
Id - Application/business workflow correlation id — distinct from
ConversationId(Reliar’s own conversation root) and acausation_id(the direct parent message). Capped atSelf::MAX_LENbytes: it lands in atextcolumn read on every claim. - Correlation
Metadata - Correlation and conversation identity for one envelope.
- Delivery
Metadata - Serialization and delivery hints for one envelope.
- Endpoint
Address - An opaque, transport-interpreted address string (a queue name, a subject, a service name —
Reliar does not care which). Capped at
Self::MAX_LENbytes. - Envelope
- An envelope: a typed or serialized body plus the metadata Reliar understands and the custom
headers it does not.
Envelope != OutboxRecord != InboxRecord— nothing here carries delivery state (attempts, leases, dead-letter bookkeeping). - Envelope
Builder - Builds an
Envelope<T>. Obtained fromEnvelope::builder. - Headers
- Application-defined metadata Reliar does not understand: a validating newtype, never a
HashMapalias and never exposed throughDeref(ADR 0011). Reserves the entirereliar-prefix (case-insensitive) so framework metadata is never duplicated here — seeMetadatafor the one canonical source of truth (ADR 0004). - Json
Serializer json - The default
Serializer: JSON viaserde_json. Ships behind the defaultjsonfeature; disable it to supply a different wire format (ADR 0010). - Message
Id - Uniquely identifies one envelope end-to-end: enqueue, storage row, wire message, and, if it fails permanently, the dead entry.
- Message
Type - A message’s name and version, carried separately so a query can filter a name across every
version. Renders as
"{name}.v{version}"via itsDisplayimpl. - Metadata
- Canonical, typed framework metadata: the single source of truth. No value here is ever
duplicated into
Headers(ADR 0004). - Request
Id - Correlates an envelope back to the inbound request (HTTP call, RPC, CLI invocation) that
caused it, so an outbound message can be traced to its trigger. Always host-supplied:
there is deliberately no
new()/Default, since a minted request id would claim an inbound request exists when none does (ADR 0038). A host wraps the id it already has withSelf::from_uuid. - Routing
Metadata - Transport-independent routing only. Kafka partition keys,
RabbitMQexchanges and NATS subject options are transport concepts and must never appear here — a transport crate derives its own wire-level routing fromSelf::destinationinstead, without adding its concept to this struct. - Trace
Context - W3C Trace Context, carried verbatim. Reliar never invents or re-derives it (ADR 0004, ADR 0020): a transport mapper writes these from an active span and reads them back on decode.
Enums§
- Content
Type Error ContentType::parsefailures.- Failure
Kind - Whether a failure is worth retrying.
- Header
Error Headers::insertfailures.- IdError
- Validation failures shared by every capped string identity newtype in
reliar-core. - Json
Error json JsonSerializerfailures.Displaynames the operation, the error class (serde_json::error::Category), and the line/column — neverserde_json::Error’s own message, which for a data error embeds a fragment of the value it rejected (e.g.invalid type: string "sk-live-…", expected u64). The full underlying error, message included, is still reachable viastd::error::Error::sourcefor a caller that deliberately wants it — that caller’s own logging then owns not leaking a payload fragment, the same rule this type upholds by default.- Settings
Error - Why a
*Settings::from_envcall failed.OutboxSettings::from_env(reliar-outbox) was the first caller; every provider’s ownfrom_envreturns this same type, so a host wiring severalfrom_envcalls handles one error type for the whole family.
Traits§
- Classify
- Implemented by every
crate::Publisher::ErrorandOutboxStore::Error(reliar-outbox) so a dispatcher can decide retry vs. dead without a downcast. Carried by the error type, not by the publisher: the error value is what crosses aJoinSetboundary into the dispatcher, so it must carry its own verdict (ADR 0008). - Envelope
Mapper - Converts a
SerializedEnvelopeto and from one transport’s native message typeM. - Message
- A type that can be built into an
Envelopeand persisted or published. - Publisher
- The wire side of the outbox. One provider implements this per transport.
- Serializer
- Converts a typed
Messagebody to and from bytes. Lives inreliar-core: it touches neither storage nor transport (ADR 0010).
Type Aliases§
- Serialized
Envelope - The persistence/transport form: an envelope whose body has already been serialized to bytes.