Skip to main content

TaskStoreConfig

Struct TaskStoreConfig 

Source
#[non_exhaustive]
pub struct TaskStoreConfig { pub max_capacity: Option<usize>, pub task_ttl: Option<Duration>, pub eviction_interval: u64, pub max_page_size: u32, pub idempotency_key_ttl: Option<Duration>, pub max_events_per_task: Option<usize>, }
Expand description

Configuration for InMemoryTaskStore.

#[non_exhaustive]: build it with Default and the with_* setters, which cover every field; a struct literal is not available outside this crate, so a field added later does not break callers.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§max_capacity: Option<usize>

Maximum number of tasks to keep in the store. Once exceeded, the oldest terminal (completed/failed/canceled/rejected) tasks are evicted first. None means no limit.

Overload behavior: if the overflow cannot be covered by terminal tasks alone, the oldest non-terminal tasks are evicted as a last resort — bounded memory is prioritized over retaining in-flight rows. An evicted in-flight task answers GetTask with task-not-found until its next event is persisted (the background processor re-saves it), so under sustained over-capacity write pressure the cap is a strong bound on steady-state size, not an absolute invariant. Size max_capacity above the realistic concurrent in-flight task count.

§task_ttl: Option<Duration>

Time-to-live for completed or failed tasks. Tasks in terminal states older than this duration are evicted on the next write operation. None means no TTL-based eviction.

§eviction_interval: u64

Number of writes between automatic eviction sweeps. Default: 64.

Amortizes the O(n) eviction cost so it doesn’t run on every single save().

§max_page_size: u32

Maximum allowed page size for list queries. Default: 1000.

Larger requested page sizes are clamped to this limit.

§idempotency_key_ttl: Option<Duration>

How long an idempotency key is kept after it is claimed. None keeps them for the life of the process, which is what every release before this one did. Default: Some(24h).

§Why this has to be bounded at all

max_capacity and task_ttl bound the number of tasks, and a key is deliberately not evicted with the task it names — dropping it there would let a late retry execute the send a second time. So nothing removed a key except the send that failed while holding it, and the index grew by one entry per keyed send for as long as the process ran.

§What expiring one costs

Exactly what the key was preventing: a retry arriving after the key expires re-executes the send rather than replaying. That trade is inherent to any expiring idempotency key, and it is why the default is a full day rather than something tidier — it has to exceed the longest window in which a client might still retry, and this SDK’s own RetryPolicy is bounded in the low tens of seconds.

A day is also comfortably above the one-hour default task_ttl, which keeps the ordering the design rests on: the key outlives the task it names, so a retry inside the window gets a replay or a clear “that task is gone”, never a second task alongside the first.

§max_events_per_task: Option<usize>

How many events one task’s log may hold before the oldest are dropped. None means no limit. Default: Some(512).

§Why this has to be bounded at all

max_capacity and task_ttl bound the number of tasks; until 0.13 nothing bounded what one task held. The log keeps a full event.clone() per append, artifact payloads included, so a streaming agent that emits 10,000 chunks leaves the store holding the folded task and a second copy of every chunk. Memory per task went from O(final task size) to O(events × event size), and the only thing that freed it was the whole task being evicted.

§Why 512

The log’s job is to let a subscriber that dropped its connection resume where it left off, so what it has to cover is a reconnect, not a run. 512 positions is roughly a 500-chunk stream — the length this repository’s own backpressure/append_volume benchmark uses as its large case — so a reconnect inside one typical response replays in full. It is deliberately not “whatever the longest run produces”: that number is unbounded and set by the agent, not by the operator.

Raise it where subscribers reconnect after long gaps and the events are small; lower it where artifact chunks are large. Truncation is safe either way — see the next paragraph — so the cost of too low a value is a resubscribe that is told it cannot be served, not one served wrongly.

§Dropping the oldest is safe, and this is what makes it safe

A reader that asks to resume from a position the log no longer holds must not be handed the surviving tail as though nothing were missing. TaskStore::earliest_event_seq reports the oldest position still held, and TaskStore::event_log_covers turns that into the question a resubscribe actually asks. Truncation never empties a log — at least one event is always kept — so the earliest position stays answerable.

Implementations§

Source§

impl TaskStoreConfig

Source

pub const fn with_idempotency_key_ttl( self, ttl: Option<Duration>, ) -> TaskStoreConfig

Sets how long an idempotency key is kept; None keeps it for the life of the process.

See idempotency_key_ttl for what expiring one costs, and why it should stay above task_ttl.

Source

pub const fn with_max_capacity(self, max: Option<usize>) -> TaskStoreConfig

Sets the maximum number of tasks kept; None is no limit. See max_capacity for what happens past it.

Source

pub const fn with_task_ttl(self, ttl: Option<Duration>) -> TaskStoreConfig

Sets the time-to-live for terminal tasks; None disables TTL eviction.

Source

pub const fn with_eviction_interval(self, writes: u64) -> TaskStoreConfig

Sets the number of writes between eviction sweeps.

Source

pub const fn with_max_page_size(self, max: u32) -> TaskStoreConfig

Sets the maximum page size for list queries.

Source

pub const fn with_max_events_per_task( self, max: Option<usize>, ) -> TaskStoreConfig

Sets how many events one task’s log keeps; None is no limit.

Some(0) is treated as Some(1): a log that keeps nothing could not report an earliest position, and a resuming subscriber would be told the log is complete when it holds nothing at all. See max_events_per_task for the default and for why dropping the oldest entries does not produce a gapped replay.

Trait Implementations§

Source§

impl Clone for TaskStoreConfig

Source§

fn clone(&self) -> TaskStoreConfig

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TaskStoreConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for TaskStoreConfig

Source§

fn default() -> TaskStoreConfig

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self> ⓘ

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more