pub struct TenantAwareInMemoryTaskStore { /* private fields */ }Expand description
Tenant-isolated in-memory TaskStore.
Maintains a separate InMemoryTaskStore per tenant, providing full
data isolation between tenants. The current tenant is determined from
TenantContext.
§Usage
use a2a_protocol_server::store::tenant::{TenantAwareInMemoryTaskStore, TenantContext};
use a2a_protocol_server::store::TaskStore;
let store = TenantAwareInMemoryTaskStore::new();
// Tenant A saves a task
TenantContext::scope("tenant-a", async {
let task = Task {
id: TaskId::new("task-1"),
context_id: ContextId::new("ctx-1"),
status: TaskStatus::with_timestamp(TaskState::Submitted),
history: None,
artifacts: None,
metadata: None,
};
store.save(&task).await.unwrap();
}).await;
// Tenant B cannot see tenant A's task
TenantContext::scope("tenant-b", async {
let result = store.get(&TaskId::new("task-1")).await.unwrap();
assert!(result.is_none());
}).await;Implementations§
Source§impl TenantAwareInMemoryTaskStore
impl TenantAwareInMemoryTaskStore
Sourcepub fn with_config(config: TenantStoreConfig) -> Self
pub fn with_config(config: TenantStoreConfig) -> Self
Creates a new tenant-aware store with custom configuration.
Sourcepub fn with_tenant_override(
self,
tenant: impl Into<String>,
config: TaskStoreConfig,
) -> Self
pub fn with_tenant_override( self, tenant: impl Into<String>, config: TaskStoreConfig, ) -> Self
Gives tenant its own TaskStoreConfig, overriding
TenantStoreConfig::per_tenant for that tenant alone.
This is the per-tenant store bound that
TenantLimits::max_stored_tasks claimed to be and could not: that field
sits on PerTenantConfig, which the handler
holds and a store never sees. Here the store owns the map and reads it
as it creates the partition.
Every field of TaskStoreConfig is overridden, not just capacity — a
tenant can be given its own TTL, eviction interval and page cap too. The
override replaces the whole config rather than merging, so build it from
per_tenant with .. if you mean to change one field:
use a2a_protocol_server::{TaskStoreConfig, TenantAwareInMemoryTaskStore};
let store = TenantAwareInMemoryTaskStore::new().with_tenant_override(
"small-fry",
TaskStoreConfig {
max_capacity: Some(100),
..TaskStoreConfig::default()
},
);A partition is created on a tenant’s first use, so an override for a tenant that already has one applies only to a store built afterwards.
Sourcepub async fn tenant_count(&self) -> usize
pub async fn tenant_count(&self) -> usize
Returns the number of active tenant partitions.
Sourcepub async fn run_eviction_all(&self)
pub async fn run_eviction_all(&self)
Runs eviction on all tenant stores.
Call periodically to clean up terminal tasks in idle tenants.
Sourcepub async fn prune_empty_tenants(&self)
pub async fn prune_empty_tenants(&self)
Removes empty tenant partitions to reclaim memory.
A partition is considered empty when its task count is zero, so this
reclaims a slot only once every task in that partition is gone —
evicted by TTL, by capacity, or deleted. It is the only way a
max_tenants slot is ever given
back, and nothing calls it for you: schedule it alongside
run_eviction_all, which is what makes
partitions empty in the first place.
Calling it will not relieve a store that is at its cap because of live
tasks; see max_tenants for why that matters.
Trait Implementations§
Source§impl Debug for TenantAwareInMemoryTaskStore
impl Debug for TenantAwareInMemoryTaskStore
Source§impl TaskStore for TenantAwareInMemoryTaskStore
impl TaskStore for TenantAwareInMemoryTaskStore
Source§fn save<'a>(
&'a self,
task: &'a Task,
) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>
fn save<'a>( &'a self, task: &'a Task, ) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>
Source§fn get<'a>(
&'a self,
id: &'a TaskId,
) -> Pin<Box<dyn Future<Output = A2aResult<Option<Task>>> + Send + 'a>>
fn get<'a>( &'a self, id: &'a TaskId, ) -> Pin<Box<dyn Future<Output = A2aResult<Option<Task>>> + Send + 'a>>
None if not found. Read moreSource§fn list<'a>(
&'a self,
params: &'a ListTasksParams,
) -> Pin<Box<dyn Future<Output = A2aResult<TaskListResponse>> + Send + 'a>>
fn list<'a>( &'a self, params: &'a ListTasksParams, ) -> Pin<Box<dyn Future<Output = A2aResult<TaskListResponse>> + Send + 'a>>
Source§fn insert_if_absent<'a>(
&'a self,
task: &'a Task,
) -> Pin<Box<dyn Future<Output = A2aResult<bool>> + Send + 'a>>
fn insert_if_absent<'a>( &'a self, task: &'a Task, ) -> Pin<Box<dyn Future<Output = A2aResult<bool>> + Send + 'a>>
Source§fn delete<'a>(
&'a self,
id: &'a TaskId,
) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>
fn delete<'a>( &'a self, id: &'a TaskId, ) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>
Auto Trait Implementations§
impl !Freeze for TenantAwareInMemoryTaskStore
impl !RefUnwindSafe for TenantAwareInMemoryTaskStore
impl !UnwindSafe for TenantAwareInMemoryTaskStore
impl Send for TenantAwareInMemoryTaskStore
impl Sync for TenantAwareInMemoryTaskStore
impl Unpin for TenantAwareInMemoryTaskStore
impl UnsafeUnpin for TenantAwareInMemoryTaskStore
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
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
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> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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 moreSource§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