Skip to main content

ValkeyStore

Struct ValkeyStore 

Source
pub struct ValkeyStore { /* private fields */ }
Available on crate feature 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.

KeyTypeContents
B s:{session id}hashsubject, 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}hashsid, seq (issue order), issued, used, sup (superseded)
B k:{session id}sorted setthe session’s token hashes, scored by seq
B u:{subject}setsession ids of a subject (in the subject’s bucket)
B ur:{subject}setids of a subject being revoked (in the subject’s bucket)
B xsorted setsession ids scored by expires_at
B isorted setsession ids scored by last_seen_at
B esorted setevents as JSON, scored by at
B c:{session id}:{kind}stringtime of the last session event claim
B c:s:{subject}:{kind}stringtime of the last subject alert claim (subject’s bucket)
B czsorted 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

Source

pub fn new(conn: ConnectionManager) -> Self

A store on an existing connection, with the default key prefix sg:.

Source

pub fn from_cluster(conn: ClusterConnection) -> Self

A store on an existing Cluster connection, with the default key prefix sg:.

Source

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.

Source

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.

Source

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

Source§

fn clone(&self) -> Self

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 ValkeyStore

Source§

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

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

impl SessionStore for ValkeyStore

Source§

fn sharded(&self) -> bool

Whether the store partitions data into buckets that must be co-located. Read more
Source§

async fn insert_session( &self, session: &SessionRecord, token: &TokenHash, ) -> Result<(), StoreError>

Stores a new session with 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>

Finds the session holding token, current or superseded.
Source§

async fn apply(&self, update: &SessionUpdate) -> Result<bool, StoreError>

Applies update atomically, in this order: Read more
Source§

async fn delete_session(&self, session_id: Uuid) -> Result<bool, StoreError>

Deletes a session and its tokens. Returns whether it existed.
Source§

async fn delete_subject_sessions( &self, subject: &str, ) -> Result<Vec<Uuid>, StoreError>

Deletes every session of subject (canonical JSON). Returns the ids it deleted.
Source§

async fn list_subject_sessions( &self, subject: &str, ) -> Result<Vec<SessionRecord>, StoreError>

Every session of 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>

Deletes sessions with expires_at <= now or last_seen_at <= idle_cutoff. Returns how many.
Source§

async fn record_event(&self, event: &SessionEvent) -> Result<(), StoreError>

Appends a security event. Stores without an event log may discard it.
Source§

async fn delete_events_before( &self, cutoff: DateTime<Utc>, ) -> Result<u64, StoreError>

Deletes events with 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>

Claims the right to report a 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 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<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> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

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> 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> IntoApi for T

Source§

fn into_api<A>(self) -> UseApi<T, A>
where T: Sized,

into UseApi
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> 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<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