How to Mock a Redis Session Store in Python
An in-memory RedisSessionStore class with TTL-based expiry, get/set/delete/exists methods, and JSON field support—perfect for testing and prototyping without a live Redis.
Python code
56 linesimport time
import json
from collections import defaultdict
class RedisSessionStore:
"""In-memory mock of a Redis-backed session store."""
def __init__(self, ttl=3600):
self._data = defaultdict(dict)
self._expires = {}
self._ttl = ttl
def set(self, session_id, field, value):
if session_id not in self._data:
self._expires[session_id] = time.time() + self._ttl
self._data[session_id][field] = value
def get(self, session_id, field):
self._evict_expired()
if session_id in self._data:
return self._data[session_id].get(field)
return None
def delete(self, session_id):
self._data.pop(session_id, None)
self._expires.pop(session_id, None)
def _evict_expired(self):
now = time.time()
for sid, expiry in list(self._expires.items()):
if expiry <= now:
self.delete(sid)
def exists(self, session_id):
self._evict_expired()
return session_id in self._data
if __name__ == "__main__":
store = RedisSessionStore(ttl=2)
store.set("user:1", "name", "Alice")
store.set("user:1", "cart", json.dumps(["item1", "item2"]))
store.set("user:2", "name", "Bob")
print("Before expiry:", store.get("user:1", "name"))
print("Exists user:1:", store.exists("user:1"))
print("All fields user:1:", store._data["user:1"])
time.sleep(3)
print("After 3s exist user:1:", store.exists("user:1"))
print("After expiry get:", store.get("user:1", "name"))
store.delete("user:2")
print("After delete exists user:2:", store.exists("user:2"))
Output
Before expiry: Alice
Exists user:1: True
All fields user:1: {'name': 'Alice', 'cart': '["item1", "item2"]'}
After 3s exist user:1: False
After expiry get: None
After delete exists user:2: False
How it works
This mock replicates Redis's hash-style storage: each session ID maps to a dict of fields. The TTL is stored alongside each session, and _evict_expired removes sessions lazily every time get or exists is called. Using defaultdict(dict) avoids manual dict initialization for new sessions. The expiry check in get and exists ensures stale sessions don't linger. While this works for unit tests, real Redis keys have server-side TTL enforcement—this mock relies on client-side timestamps.
Common mistakes
- Forgetting to call _evict_expired in get/exists, leading to stale reads
- Using a single global TTL instead of per-session timestamps stored at creation
- Assuming the mock thread-safe; add locks for concurrent access
- Storing non-serializable objects without json.dumps for fields
Variations
- Use fakeredis library for a drop-in mock with full Redis command support
- Implement expiry as a separate background thread that cleans expired sessions periodically
Real-world use cases
- Unit testing Flask/Django session logic without needing a Redis server in CI.
- Development environment where auth sessions are mocked for local frontend work.
- Prototyping session-based rate limiting before migrating to production Redis.
Sponsored
More from Auth & security at scale
- ACME LetsEncrypt Mock Challenge Server in Python medium
- AES GCM encryption and decryption in Python medium
- Build a Mock OIDC Userinfo Endpoint in Python with Flask easy
- ChaCha20-Poly1305 mock in Python medium
- ECDH key agreement in Python with cryptography medium
- Enforce TLS 1.2 Minimum in Python easy
Keep learning
Related tutorials and quizzes for this topic.