Skip to content

First Steps

The smallest grelmicro app is one pattern and one provider. The pattern carries no backend reference and finds the provider on its own.

Install

pip install "grelmicro[redis]"

See the installation guide for uv, poetry, and the other backend extras.

Mental model

  • Pattern: the object your app calls, such as Lock("cart") or RateLimiter.sliding_window("api", ...).
  • Provider: owns a connection, such as RedisProvider.
  • Component: wires a backend into the app, such as Cache or Coordination. A Provider on its own registers one for every kind it serves, so you often name none.
  • Adapter: the concrete backend implementation. Providers usually hide it.
  • Ambient binding: micro.install(app) lets request and message handlers find the current Grelmicro app.

Your first app

Guard a shared resource with a distributed Lock. The provider says where the lock state lives, so every worker takes the same lock.

from grelmicro import Grelmicro
from grelmicro.coordination import Lock
from grelmicro.providers.redis import RedisProvider

redis = RedisProvider("redis://localhost:6379/0")
micro = Grelmicro(uses=[redis])

lock = Lock("cart")


async def checkout() -> None:
    async with lock:
        ...


async def main() -> None:
    # The lock resolves its backend inside the app scope.
    async with micro:
        await checkout()

Start Redis with one command:

docker run -d -p 6379:6379 redis

Three things happen here:

  1. Lock("cart") builds a lock named cart with default settings.
  2. RedisProvider(...) says where the shared state lives.
  3. Grelmicro(uses=[...]) wires it into the app.

The lock carries no backend reference. It finds one when it is used, inside async with micro:, which is why checkout() is called from there. In a web app micro.install(app) extends that scope to your request handlers, so handlers need no async with.

One caller holds cart at a time. The next caller waits for the release.

Construct a pattern

Every pattern is built the same way. Pass the name first, then tune with keyword arguments:

from grelmicro.coordination import Lock

lock = Lock("cart", lease_duration=60)

Patterns with variants use factory methods:

from grelmicro.resilience import RateLimiter

api = RateLimiter.sliding_window("api", limit=100, window=60)

Decorators take the same keyword arguments:

from grelmicro.cache import cached

@cached(ttl=30)
async def get_user(user_id: int) -> User:
    ...

Next

You built a pattern and wired it into an app. Next, wire it into a web framework with micro.install(app).