How to Build an In-Memory Service Registry Mock in Python

A simple in-memory ServiceRegistry class to register, retrieve, list, and unregister microservice endpoints or configs using a dict, with KeyError guards.

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

Python code

32 lines
Python 3.9+
class ServiceRegistry:
    def __init__(self):
        self._services = {}

    def register(self, name, service):
        self._services[name] = service

    def unregister(self, name):
        if name not in self._services:
            raise KeyError(f"Service '{name}' not found")
        del self._services[name]

    def get(self, name):
        if name not in self._services:
            raise KeyError(f"Service '{name}' not found")
        return self._services[name]

    def list_services(self):
        return sorted(self._services.keys())


if __name__ == "__main__":
    registry = ServiceRegistry()
    registry.register("database", {"host": "localhost", "port": 5432})
    registry.register("cache", {"host": "localhost", "port": 6379})

    print("Registered services:", registry.list_services())
    print("Database config:", registry.get("database"))
    print("Cache config:", registry.get("cache"))

    registry.unregister("cache")
    print("After unregistering cache:", registry.list_services())

Output

stdout
Registered services: ['database', 'cache']
Database config: {'host': 'localhost', 'port': 5432}
Cache config: {'host': 'localhost', 'port': 6379}
After unregistering cache: ['database']

How it works

The ServiceRegistry class wraps an internal dict _services that stores services by name. register simply adds a new key-value pair, while get and unregister use membership checks (in) to raise a descriptive KeyError if the service doesn't exist. list_services uses sorted() on the dict keys to return a deterministic, alphabetically ordered list. Because the registry is in-memory, it's ideal for mocking in tests or for single-process prototypes, not for distributed production use.

Common mistakes

  • Forgetting to check existence before `unregister`, which silently removes nothing or throws a raw KeyError.
  • Using `self._services.keys()` directly in `list_services` without sorting, leading to non-deterministic output order.
  • Sharing a single registry across threads or processes without locks, causing race conditions.
  • Storing mutable service objects and unintentionally modifying them from outside the registry.

Variations

  1. Use a `defaultdict` if you want unregistered lookups to return a default value instead of raising.
  2. Add a `threading.RLock` to make the registry thread-safe.
  3. Return a copy of the service (e.g., `copy.deepcopy`) to prevent external mutation.

Real-world use cases

  • Unit test a microservice that discovers dependencies via a lightweight, in-memory registry substitute.
  • Prototype service discovery config in a monolith before moving to a real service mesh or DNS-based registry.
  • In a CLI tool, maintain a registry of pluggable commands registered at startup from different modules.

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.