pub struct ValkeyStore { /* private fields */ }valkey only.Expand description
A SessionStore on Valkey or Redis, standalone or Cluster.
Every write that touches more than one key runs as a Lua script, so it is atomic across any number of processes sharing the server. Requires Valkey 7.2+ or Redis 7.0+.
§Cluster
Connect with connect_cluster or
from_cluster. Keys are split into 256 fixed buckets, and every key
carries its bucket as a hash tag ({bb}), so a session, its tokens and its indexes always
live in one hash slot and each script runs on one node. The bucket is the last byte of the
session id, the first byte of a token’s hash, or the first byte of the SHA-256 of a subject.
Guard mines tokens so that a session’s tokens share its bucket; the store
rejects writes where they do not.
The subject index is the one structure that spans buckets: a session id sits in its subject’s
set while the session lives in its own bucket, so subject-wide operations are eventually
consistent. delete_subject_sessions moves the set
aside, deletes each session in its bucket and then drops the moved ids. If the caller
crashes in between, the leftover ids stay pending and the next revoke for the subject
finishes them. A session created while a revoke runs is either revoked or its creator gets an
error and the session is removed. list_subject_sessions
includes sessions that are mid-revoke.
delete_expired and
delete_events_before visit all 256 buckets.
§Data layout
All keys start with the key prefix followed by the bucket tag, written
B here (for example sg:{0a}:). Timestamps are microseconds since the Unix epoch as
decimal integers.
| Key | Type | Contents |
|---|---|---|
B s:{session id} | hash | subject, created, auth, seen, expires, step_up, baseline (JSON), origin (JSON, absent before 0.2), cur (current token), seq (token counter), exp_ms |
B t:{token hash hex} | hash | sid, seq (issue order), issued, used, sup (superseded) |
B k:{session id} | sorted set | the session’s token hashes, scored by seq |
B u:{subject} | set | session ids of a subject (in the subject’s bucket) |
B ur:{subject} | set | ids of a subject being revoked (in the subject’s bucket) |
B x | sorted set | session ids scored by expires_at |
B i | sorted set | session ids scored by last_seen_at |
B e | sorted set | events as JSON, scored by at |
B c:{session id}:{kind} | string | time of the last session event claim |
B c:s:{subject}:{kind} | string | time of the last subject alert claim (subject’s bucket) |
B cz | sorted set | {session id}:{kind} and s:{subject}:{kind} claims scored by claim time |
Session, token and per-session token-set keys expire at the session’s absolute expiry and
subject sets at their last session’s expiry, so Valkey cleans up even if
delete_expired never runs. Because those TTLs follow the
server’s wall clock, sessions whose expires_at is already in the past vanish immediately.
Claim keys expire after their window.
Subjects are passed to scripts as data, never as code.
Cheap to clone; clones share the connection.
Implementations§
Source§impl ValkeyStore
impl ValkeyStore
Sourcepub fn new(conn: ConnectionManager) -> Self
pub fn new(conn: ConnectionManager) -> Self
A store on an existing connection, with the default key prefix sg:.
Sourcepub fn from_cluster(conn: ClusterConnection) -> Self
pub fn from_cluster(conn: ClusterConnection) -> Self
A store on an existing Cluster connection, with the default key prefix sg:.
Sourcepub async fn connect_cluster<T: IntoConnectionInfo>(
nodes: impl IntoIterator<Item = T>,
) -> Result<Self, RedisError>
pub async fn connect_cluster<T: IntoConnectionInfo>( nodes: impl IntoIterator<Item = T>, ) -> Result<Self, RedisError>
Connects to a Valkey or Redis Cluster through any of its nodes (redis://, rediss://
or valkey:// URLs), with the default key prefix sg:.
§Errors
If a URL is invalid or no node is reachable.
Sourcepub async fn connect(url: &str) -> Result<Self, RedisError>
pub async fn connect(url: &str) -> Result<Self, RedisError>
Connects to url (redis://, rediss:// or valkey://), with the default key prefix
sg:.
§Errors
If the URL is invalid or the server is unreachable.
Sourcepub fn key_prefix(self, prefix: impl Into<String>) -> Self
pub fn key_prefix(self, prefix: impl Into<String>) -> Self
Prefixes every key with prefix, so several apps can share one server. Defaults to
sg:.
§Panics
If prefix contains { or }: the store puts its own hash tag after the prefix, and a
brace in the prefix would change which slot keys land in.
Trait Implementations§
Source§impl Clone for ValkeyStore
impl Clone for ValkeyStore
Source§impl Debug for ValkeyStore
impl Debug for ValkeyStore
Source§impl SessionStore for ValkeyStore
impl SessionStore for ValkeyStore
Source§async fn insert_session(
&self,
session: &SessionRecord,
token: &TokenHash,
) -> Result<(), StoreError>
async fn insert_session( &self, session: &SessionRecord, token: &TokenHash, ) -> Result<(), StoreError>
token as its current token (issued_at = created_at,
unused, not superseded).Source§async fn find_by_token(
&self,
token: &TokenHash,
) -> Result<Option<TokenLookup>, StoreError>
async fn find_by_token( &self, token: &TokenHash, ) -> Result<Option<TokenLookup>, StoreError>
token, current or superseded.Source§async fn apply(&self, update: &SessionUpdate) -> Result<bool, StoreError>
async fn apply(&self, update: &SessionUpdate) -> Result<bool, StoreError>
update atomically, in this order: Read moreSource§async fn delete_session(&self, session_id: Uuid) -> Result<bool, StoreError>
async fn delete_session(&self, session_id: Uuid) -> Result<bool, StoreError>
Source§async fn delete_subject_sessions(
&self,
subject: &str,
) -> Result<Vec<Uuid>, StoreError>
async fn delete_subject_sessions( &self, subject: &str, ) -> Result<Vec<Uuid>, StoreError>
subject (canonical JSON). Returns the ids it deleted.Source§async fn list_subject_sessions(
&self,
subject: &str,
) -> Result<Vec<SessionRecord>, StoreError>
async fn list_subject_sessions( &self, subject: &str, ) -> Result<Vec<SessionRecord>, StoreError>
subject (canonical JSON), including expired ones not yet purged.Source§async fn delete_expired(
&self,
now: DateTime<Utc>,
idle_cutoff: DateTime<Utc>,
) -> Result<u64, StoreError>
async fn delete_expired( &self, now: DateTime<Utc>, idle_cutoff: DateTime<Utc>, ) -> Result<u64, StoreError>
expires_at <= now or last_seen_at <= idle_cutoff. Returns how
many.Source§async fn record_event(&self, event: &SessionEvent) -> Result<(), StoreError>
async fn record_event(&self, event: &SessionEvent) -> Result<(), StoreError>
Source§async fn delete_events_before(
&self,
cutoff: DateTime<Utc>,
) -> Result<u64, StoreError>
async fn delete_events_before( &self, cutoff: DateTime<Utc>, ) -> Result<u64, StoreError>
at < cutoff. Returns how many. Also deletes event claims older
than cutoff.Source§async fn claim_event(
&self,
scope: ClaimScope<'_>,
kind: EventKind,
now: DateTime<Utc>,
window: TimeDelta,
) -> Result<bool, StoreError>
async fn claim_event( &self, scope: ClaimScope<'_>, kind: EventKind, now: DateTime<Utc>, window: TimeDelta, ) -> Result<bool, StoreError>
kind event for scope, for deduplication across
processes. Succeeds (true) unless a claim for the same scope and kind was made after
now - window, and records now as the new claim when it does. Session and subject
claims are independent. Must be atomic across processes. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for ValkeyStore
impl !UnwindSafe for ValkeyStore
impl Freeze for ValkeyStore
impl Send for ValkeyStore
impl Sync for ValkeyStore
impl Unpin for ValkeyStore
impl UnsafeUnpin for ValkeyStore
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
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 more