How to implement read-your-writes sticky routing in Python

A mock StickyRouter class that routes all requests for the same key to the same node, ensuring read-after-write consistency.

Easy Python 3.9+ Aug 9, 2026 Microservices patterns 13 views 0 copies

Python code

32 lines
Python 3.9+
import random

class StickyRouter:
    def __init__(self, nodes):
        self.nodes = nodes
        self.routes = {}

    def route(self, key):
        if key not in self.routes:
            self.routes[key] = random.choice(self.nodes)
        return self.routes[key]

    def read(self, key):
        node = self.routes.get(key, random.choice(self.nodes))
        return f"Read '{key}' from {node}"

    def write(self, key, value):
        node = self.route(key)
        return f"Write '{key}={value}' to {node}"


if __name__ == "__main__":
    router = StickyRouter(["node-a", "node-b", "node-c"])

    print(router.write("user:42", "Alice"))
    print(router.read("user:42"))

    # Simulate another write — should hit the same node
    print(router.write("user:42", "Alice-updated"))

    # Different key gets a different (arbitrary) node
    print(router.write("user:99", "Bob"))

Output

stdout
Write 'user:42=Alice' to node-b
Read 'user:42' from node-b
Write 'user:42=Alice-updated' to node-b
Write 'user:99=Bob' to node-a

How it works

The route method assigns a random node the first time a key is seen, then caches that mapping in self.routes. The write method always calls route so subsequent writes for the same key hit the same node, giving read-your-writes consistency when a matching read follows. The read method uses self.routes.get(key, random.choice(self.nodes)) so a key that was never written gets a fresh arbitrary node. Because the mapping is in-memory, this mock demonstrates the pattern without a real load balancer or session store.

Common mistakes

  • Using a new random choice on every read/write, which breaks stickiness
  • Not handling keys that were never written — reads should fall back to a random node
  • Forgetting that the routing table must be shared across processes or instances in real deployments

Variations

  1. Use a consistent hash ring (e.g., hash of key modulo number of nodes) for deterministic routing without a route table
  2. Back the routing map with Redis or a database so stickiness survives restarts

Real-world use cases

  • Directing a user's session requests to the same backend cache or database shard for consistency.
  • Keeping API callers pinned to the same worker that holds an in-memory rate limit or cursor state.
  • Routing sticky consumers to the same Kafka partition or message queue for ordered processing.

Sponsored

Run this sample

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

Open editor

More from Microservices patterns

Related tutorials and quizzes for this topic.