pub struct TenantContext;Expand description
全局租户上下文 — 持有当前请求的 tenant_id
§线程安全
内部使用线程局部存储(thread_local!),每个线程持有独立的租户上下文。
在 axum 中间件(运行于请求线程)中设置后,同线程的业务代码通过 Self::current() 读取。
多线程并发场景下各线程互不干扰,适合测试并行执行。
Implementations§
Source§impl TenantContext
impl TenantContext
Sourcepub fn set_current(tenant_id: i64)
pub fn set_current(tenant_id: i64)
设置当前租户 ID
Sourcepub fn require_current() -> Result<i64, TenantError>
pub fn require_current() -> Result<i64, TenantError>
获取当前租户 ID,未设置时返回错误
Sourcepub fn guard() -> Result<TenantGuard, TenantError>
pub fn guard() -> Result<TenantGuard, TenantError>
创建 TenantGuard — 在 await 前捕获当前租户 ID
§为什么需要 Guard
TenantContext 基于 thread_local! 存储。在 tokio 异步运行时中,
.await 可能导致任务切换到不同线程,使 thread_local 值静默改变。
在业务代码需要跨 await 使用租户 ID 时,应先在 await 前调用本方法
创建 TenantGuard,之后通过 guard.tenant_id() 访问(而非 TenantContext::current())。
§使用示例
ⓘ
async fn handle_request() -> Result<(), TenantError> {
// 在第一个 await 之前捕获租户 ID
let guard = TenantContext::guard()?;
// 以下操作可能跨越 await,但 guard 持有正确的 tenant_id
let data = fetch_from_db(guard.tenant_id()).await?;
process(data, guard.tenant_id()).await?;
Ok(())
}§安全保证
guard.tenant_id()返回创建时捕获的值,不受线程切换影响guard.assert_current()可验证当前 thread_local 是否与捕获值一致 (用于检测中间件是否正确设置了上下文)
Auto Trait Implementations§
impl Freeze for TenantContext
impl RefUnwindSafe for TenantContext
impl Send for TenantContext
impl Sync for TenantContext
impl Unpin for TenantContext
impl UnsafeUnpin for TenantContext
impl UnwindSafe for TenantContext
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
Mutably borrows from an owned value. Read more
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
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> ⓘ
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 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> ⓘ
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 moreSource§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
The inverse inclusion map: attempts to construct
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
Checks if
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
Use with care! Same as
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
The inclusion map: converts
self to the equivalent element of its superset.