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.

Medium Python 3.9+ Aug 9, 2026 Auth & security at scale 12 views 0 copies

Python code

56 lines
Python 3.9+
import 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

stdout
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

  1. Use fakeredis library for a drop-in mock with full Redis command support
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Auth & security at scale

Related tutorials and quizzes for this topic.