pub struct ObservabilityConfig {
pub max_event_bytes: usize,
pub max_stream_events: u64,
pub max_batch_events: Option<usize>,
pub max_batch_hold_ms: Option<u64>,
}Expand description
Agent-observability transcript settings from [observability]: retention
bounds, and the transcript drain’s flush policy.
The two RETENTION knobs default (they guard the durable O keyspace against
unbounded growth): max_event_bytes truncates one oversized transcript event
before it is persisted, and max_stream_events caps how many events one
(workflow, activity, attempt) stream retains (one marker record is
persisted at the cap; live streaming continues).
The two FLUSH knobs have no default and are required — see
Self::max_batch_events.
Fields§
§max_event_bytes: usizeCeiling on one persisted transcript event’s serialized size, bytes.
max_stream_events: u64Ceiling on retained events per (workflow, activity, attempt) stream.
max_batch_events: Option<usize>Maximum transcript events the drain commits in ONE durable append.
Required; no default — an embedder-built config that omits it
refuses to start; a config FILE that omits it is healed at boot with
the declared default (64, the teaching configs’ value) by
config::heal.
Every durable commit re-persists its whole containing storage leaf as a new permanent blob, so committing one event at a time made the store cost of a run linear in event COUNT: measured 2026-08-17, a 136 KB status sweep left 73.7 MB of permanent store (540x) and a single 2,359-byte append bought a 2,303,416-byte blob. Batching divides that count by (up to) this number.
There is deliberately no shipped value: the trade between store cost and
how many events one refused commit can lose is the operator’s, and an
invented default would silently make it for them — the boot-side heal
is the one deliberate exception, minting the teaching value into a
FILE visibly, with a logged name and a preserved backup. An explicit
zero fails startup with
OBSERVABILITY_MAX_BATCH_EVENTS_REQUIRED, the same
explicit-no-default guard websocket.cluster_broadcast_capacity uses;
the heal never rewrites a present value.
max_batch_hold_ms: Option<u64>How long, in milliseconds, the drain may hold a PARTIAL batch open
waiting for it to fill. Required; no default — but 0 is a valid,
meaningful setting: never wait, commit whatever is already queued.
This is the only knob here that touches durability timing. Transcript
events already wait in an in-memory queue before they are committed, and
everything queued there is lost if the process dies; this value bounds
how much LONGER an event may wait, and therefore how much transcript a
kill-9 can cost. It buys commits: at 0 only events that genuinely
arrived together share a commit. The O keyspace is observability, never
workflow replay authority, which is why the trade is offered at all.
Absence refuses OBSERVABILITY_MAX_BATCH_HOLD_MS_REQUIRED for an
embedder-built config; a config FILE is healed at boot with the
declared default (200) by config::heal.
Implementations§
Source§impl ObservabilityConfig
impl ObservabilityConfig
Sourcepub fn with_flush_policy(
max_batch_events: usize,
max_batch_hold_ms: u64,
) -> Self
pub fn with_flush_policy( max_batch_events: usize, max_batch_hold_ms: u64, ) -> Self
The default retention bounds with the REQUIRED flush policy stated.
For an embedder that builds its ServerConfig in code rather than from
a file: Default deliberately leaves the flush policy unruled (so a
server built from it refuses to start), and this is how such a caller
states its ruling in one line. max_batch_hold_ms of 0 means the drain
never holds a partial batch open.
Trait Implementations§
Source§impl Clone for ObservabilityConfig
impl Clone for ObservabilityConfig
Source§fn clone(&self) -> ObservabilityConfig
fn clone(&self) -> ObservabilityConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for ObservabilityConfig
Source§impl Debug for ObservabilityConfig
impl Debug for ObservabilityConfig
Source§impl Default for ObservabilityConfig
impl Default for ObservabilityConfig
Source§fn default() -> Self
fn default() -> Self
The retention bounds fall back to their documented defaults; the flush
policy does NOT — None here is “the operator has not ruled”. For an
embedder-built config the boot path turns that into a refusal to
start; for a config FILE the boot-side heal (config::heal) inserts
the declared defaults visibly instead.
Source§impl<'de> Deserialize<'de> for ObservabilityConfigwhere
ObservabilityConfig: Default,
impl<'de> Deserialize<'de> for ObservabilityConfigwhere
ObservabilityConfig: Default,
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for ObservabilityConfig
Source§impl PartialEq for ObservabilityConfig
impl PartialEq for ObservabilityConfig
impl StructuralPartialEq for ObservabilityConfig
Auto Trait Implementations§
impl Freeze for ObservabilityConfig
impl RefUnwindSafe for ObservabilityConfig
impl Send for ObservabilityConfig
impl Sync for ObservabilityConfig
impl Unpin for ObservabilityConfig
impl UnsafeUnpin for ObservabilityConfig
impl UnwindSafe for ObservabilityConfig
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoMaybeUndefined<T> for T
impl<T> IntoMaybeUndefined<T> for T
Source§fn into_maybe_undefined(self) -> MaybeUndefined<T>
fn into_maybe_undefined(self) -> MaybeUndefined<T>
Source§impl<T> IntoOption<T> for T
impl<T> IntoOption<T> for T
Source§fn into_option(self) -> Option<T>
fn into_option(self) -> Option<T>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request