Files
kaya/packages/kaya-session-redis/src/kaya/session/redis/_store.py
T
woggioni 08370c4963 Rename kaya.session_redis → kaya.session.redis
- Move src/kaya/session_redis/ → src/kaya/session/redis/
- Update pyproject.toml version_file path
- Update all import references (tests, READMEs, root README)
2026-07-23 16:02:56 +00:00

58 lines
2.0 KiB
Python

import pickle
from typing import Any, Callable, Optional, cast
from redis.asyncio import Redis
from kaya.session import Session, SessionStore
class RedisSessionStore(SessionStore):
"""Redis-backed session store.
Suitable for multi-process and multi-host deployments: session data is
shared between all application instances connected to the same Redis
server.
Server-side expiry is delegated to Redis key TTLs. When ``max_age`` is
provided, active sessions slide the expiry window on each access.
Session data is serialized with ``pickle`` by default, so arbitrary
Python objects can be stored. Custom serializers can be plugged in via
the ``dumps``/``loads`` arguments. Only connect this store to a trusted
Redis server, as pickle deserialization of untrusted data is unsafe.
"""
def __init__(
self,
client: Redis,
prefix: str = "kaya:session:",
dumps: Callable[[dict[str, Any]], bytes] = pickle.dumps,
loads: Callable[[bytes], dict[str, Any]] = pickle.loads,
) -> None:
self._client = client
self._prefix = prefix
self._dumps = dumps
self._loads = loads
def _key(self, session_id: str) -> str:
return f"{self._prefix}{session_id}"
async def load(self, session_id: str, max_age: Optional[int] = None) -> Optional[Session]:
key = self._key(session_id)
payload = await self._client.get(key)
if payload is None:
return None
if max_age is not None:
await self._client.expire(key, max_age)
data = self._loads(cast(bytes, payload))
return Session(session_id, data)
async def save(self, session_id: str, session: Session, max_age: Optional[int] = None) -> None:
payload = self._dumps(dict(session))
await self._client.set(self._key(session_id), payload, ex=max_age)
async def delete(self, session_id: str) -> None:
await self._client.delete(self._key(session_id))