Skip to main content

grelmicro is a lightweight toolkit for building Python applications that need to coordinate work across processes

Project description

grelmicro

Async-first toolkit. Microservice patterns inside.

A Python toolkit for distributed systems: microservices, modular monoliths, and self-contained systems.

PyPI - Version PyPI - Python Version License: MIT codecov uv Ruff ty

Project status: Active development. grelmicro is pre-1.0. The public API is not yet stable. Breaking changes are allowed on MINOR bumps (0.14.00.15.0) and never on PATCH. Pin the minor: grelmicro>=0.14.0,<0.15.0. After 1.0.0, standard semver applies. See the versioning policy.


Documentation: https://grelinfo.github.io/grelmicro/

Source Code: https://github.com/grelinfo/grelmicro


Why grelmicro

Stop reinventing the wheel. grelmicro ships microservice patterns as small, composable modules with pluggable backends: locks, rate limits, circuit breakers, cache, logging, health checks, and task scheduling. Async-first, type-safe, and battle-tested in production.

It is built for any Python application that coordinates work across processes, workers, or replicas. The same primitives serve every distributed system, whether you call it microservices, a modular monolith, or a self-contained system. A distributed lock is a distributed lock whether your system is one process or fifty. It fits naturally into cloud-native applications, containerized apps, and Kubernetes deployments.

  • Micro: one focused primitive per module, each a canonical microservice pattern (distributed lock, leader election, rate limiter, circuit breaker, health check API, externalised configuration).
  • Fast: small footprint by design. We keep the layers thin so your code stays quick.
  • Async-first: every I/O call is async / await. Drops into FastAPI, FastStream, and any asyncio-based stack.
  • Backend-agnostic: each primitive is a protocol. Swap Redis for PostgreSQL or SQLite without touching application code.
  • Railguarded: 100% pytest coverage, ty-checked, ruff-linted, Pydantic-validated. Pre-1.0 API may shift on minor bumps. 1.x commits to standard semver.

Already using aiocache, slowapi, pybreaker, tenacity, or aioredlock? See the comparison page for a per-domain breakdown.

Modules

Module Summary
Cache @cached decorator with per-key stampede protection. In-memory TTLCache or RedisCacheAdapter.
Synchronization Distributed Lock, TaskLock, LeaderElection. Redis, PostgreSQL, SQLite, Kubernetes, in-memory.
Task Scheduler Periodic task execution with optional distributed locking. Lightweight, not a Celery replacement.
Resilience Circuit Breaker and Rate Limiter with pluggable algorithms (TokenBucketConfig, GCRAConfig).
Logging 12-factor logging with JSON, LOGFMT, TEXT, or PRETTY output, structured error rendering, and OpenTelemetry trace context.
Tracing Unified instrumentation. @instrument creates OpenTelemetry spans and enriches log records with structured context.
Health Health check registry with concurrent runners and FastAPI liveness / readiness integration.
JSON Fast JSON via orjson when available, with automatic fallback to stdlib json.

Installation

pip install grelmicro

See the Installation guide for uv and poetry commands, plus optional extras for Redis, PostgreSQL, SQLite, Kubernetes, OpenTelemetry, and structlog.

Example

FastAPI integration

Create a file main.py with:

import logging
from contextlib import asynccontextmanager

from fastapi import FastAPI, HTTPException, Request

from grelmicro import Grelmicro
from grelmicro.cache import Cache, JsonSerializer, TTLCache, cached
from grelmicro.health import HealthChecks
from grelmicro.log import configure as configure_logging
from grelmicro.providers.redis import RedisProvider
from grelmicro.resilience import (
    CircuitBreaker,
    RateLimit,
    RateLimitExceededError,
    RateLimiter,
)
from grelmicro.sync import LeaderElection, Lock, Sync
from grelmicro.task import Tasks

logger = logging.getLogger(__name__)

# === grelmicro app: one container, one lifespan ===
tasks = Tasks()
health = HealthChecks()
leader = LeaderElection("leader-election")
tasks.add_task(leader)

redis = RedisProvider("redis://localhost:6379/0")

micro = Grelmicro(uses=[
    redis,
    Sync(redis),
    Cache(redis),
    RateLimit(redis),
    tasks,
    health,
])

# === Patterns declared once at module load, resolved at use time ===
ttl_cache = TTLCache(ttl=300, serializer=JsonSerializer())
lock = Lock("shared-resource")
cb = CircuitBreaker("my-service")
api_limiter = RateLimiter.gcra("api", limit=100, window=60)


# === FastAPI lifespan ===
@asynccontextmanager
async def lifespan(app):
    configure_logging()
    async with micro:
        yield


app = FastAPI(lifespan=lifespan)


# --- Cache: avoid redundant database queries ---
@cached(ttl_cache)
async def get_user(user_id: int) -> dict:
    return {"id": user_id, "name": "Alice"}


@app.get("/users/{user_id}")
async def read_user(user_id: int):
    return await get_user(user_id)


# --- Circuit Breaker: protect calls to an unreliable service ---
@app.get("/")
async def read_root():
    async with cb:
        return {"Hello": "World"}


# --- Rate Limiter: protect endpoints from overload ---
@app.get("/api")
async def api_endpoint(request: Request):
    try:
        await api_limiter.acquire_or_raise(key=request.client.host)
    except RateLimitExceededError as exc:
        raise HTTPException(
            status_code=429,
            detail="Too many requests",
            headers={"Retry-After": str(int(exc.retry_after))},
        )
    return {"status": "ok"}


# --- Distributed Lock: synchronize access to a shared resource ---
@app.get("/protected")
async def protected():
    async with lock:
        return {"status": "ok"}


# --- Interval Task: run locally on every worker ---
@tasks.interval(seconds=5)
def heartbeat():
    logger.info("heartbeat")


# --- Distributed Task: run once per interval across all workers ---
@tasks.interval(seconds=60, max_lock_seconds=300)
def cleanup():
    logger.info("cleanup")


# --- Leader-gated Task: only the leader executes ---
@tasks.interval(seconds=10, leader=leader)
def leader_only_task():
    logger.info("leader task")

The key shape:

  • One container, one lifespan. Grelmicro(uses=[...]) lists every Provider, Component, and active manager. async with micro: opens them all in order, closes in reverse.
  • One Provider, many Components. Sync(redis), Cache(redis), RateLimit(redis) all share the same RedisProvider pool. The Provider holds the connection, the Components attach to it.
  • Patterns are declared at module load. Lock("cart"), TTLCache(ttl=60), CircuitBreaker("svc") carry no backend reference. They resolve through the active app inside async with. The same Lock works in production with Redis and in tests with MemorySyncAdapter, no rewiring.
  • Pay only for what you import. import grelmicro does not pull in redis, psycopg, or any other vendor SDK. First-party Providers live under grelmicro.providers.{vendor} and load only when you import them.

For multiple Redis instances, separate names, or test overrides, see the docs.

License

This project is licensed under the terms of the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grelmicro-0.22.0.tar.gz (533.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grelmicro-0.22.0-py3-none-any.whl (156.6 kB view details)

Uploaded Python 3

File details

Details for the file grelmicro-0.22.0.tar.gz.

File metadata

  • Download URL: grelmicro-0.22.0.tar.gz
  • Upload date:
  • Size: 533.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for grelmicro-0.22.0.tar.gz
Algorithm Hash digest
SHA256 d0edfbddc969c75bbf5a812c2f6d90133913c314b89938522763122bcfad416d
MD5 e7302561bf08bfeb56ba13ebf56fbe9c
BLAKE2b-256 b65cd529f9110fb75c6f4aa088eb3638ce822d22a46383373f4a5b00eb35fa65

See more details on using hashes here.

Provenance

The following attestation bundles were made for grelmicro-0.22.0.tar.gz:

Publisher: release.yml on grelinfo/grelmicro

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file grelmicro-0.22.0-py3-none-any.whl.

File metadata

  • Download URL: grelmicro-0.22.0-py3-none-any.whl
  • Upload date:
  • Size: 156.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for grelmicro-0.22.0-py3-none-any.whl
Algorithm Hash digest
SHA256 efd9b583679b6e08ac76c4f63ee7e1aa4ff3b08d302ff97dcf75503f28bca3c1
MD5 37a96698181132103f1d30a5f3101aa8
BLAKE2b-256 bbeddb566e4936740406731be655ff1ca7365eed68c4f0cdecbf7889d5381f09

See more details on using hashes here.

Provenance

The following attestation bundles were made for grelmicro-0.22.0-py3-none-any.whl:

Publisher: release.yml on grelinfo/grelmicro

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page