Skip to content

loguntsovae/python-service-kit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

python-service-kit

A production-ready FastAPI microservice template with batteries included. Clone it, rename the service, and start building — the observability, health probing, and Kubernetes plumbing are already wired up.

Features

  • Structured JSON logging via structlog with automatic correlation ID propagation through all log lines
  • Prometheus metrics middleware: request counts, latencies, and active request gauge out of the box
  • Liveness and readiness probes with separate semantics (see Architecture Decisions below)
  • Correlation ID and Request ID headers propagated end-to-end
  • Async SQLAlchemy 2.0 session management with connection pool tuning
  • Type-safe configuration via pydantic-settings — misconfiguration fails at startup, not at runtime
  • Kubernetes manifests: Deployment, Service, HorizontalPodAutoscaler
  • GitHub Actions CI with coverage reporting

Quick Start

git clone git@github.com:loguntsovae/python-service-kit.git my-service
cd my-service
cp .env.example .env
pip install -e ".[test]"
uvicorn app.main:app --reload

The service starts on http://localhost:8000.

  • GET /health — liveness probe
  • GET /ready — readiness probe
  • GET /metrics — Prometheus metrics

Running Tests

pytest tests/ -v --cov=app --cov-report=term-missing

Architecture Decisions

structlog for logging

structlog outputs newline-delimited JSON by default and uses Python's contextvars to carry the request context (request_id, correlation_id, method, path) into every log line emitted during a request — including lines from deep inside business logic. No need to thread a logger or context object through function arguments.

Liveness vs. readiness separation

/health answers the question "is the process alive?" — it always returns 200 as long as the Python process is running. Kubernetes restarts pods whose liveness probe fails.

/ready answers "can this pod serve traffic?" — it checks real dependencies (database, etc.). Kubernetes stops routing requests to pods whose readiness probe fails without restarting them. This prevents cascading failures when a downstream dependency goes down: pods become temporarily unready rather than crash-looping.

Non-root Dockerfile

The container runs as UID 1000. Kubernetes security policies commonly require runAsNonRoot: true, and running as root inside a container unnecessarily widens the blast radius of a container escape. The Dockerfile creates a dedicated app user and switches to it before the CMD.

Pydantic Settings for configuration

pydantic-settings reads environment variables (and optionally a .env file) and validates every field's type before the application starts. If DATABASE_URL is missing or DB_POOL_SIZE is not an integer, the process exits immediately with a descriptive error rather than failing 10 minutes into a request. .env.example documents every supported variable.

Project Structure

app/
  config.py      — Settings loaded from environment
  logging.py     — structlog configuration
  metrics.py     — Prometheus counters, histograms, gauge
  middleware.py  — ObservabilityMiddleware (metrics + correlation IDs)
  health.py      — /health and /ready endpoints
  db.py          — Async SQLAlchemy engine and session factory
  main.py        — FastAPI app factory and lifespan handler
tests/
  conftest.py    — ASGI test client fixture
  test_health.py — Health probe tests
k8s/
  deployment.yaml
  service.yaml
  hpa.yaml

About

Production-ready FastAPI microservice template — Prometheus, structured logging, Vault secrets, async SQLAlchemy, K8s manifests

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors