Skip to content

A demo project showcasing multi-tenant microservices with FastAPI, PostgreSQL, RabbitMQ, Celery, and Docker. Includes user authentication, campaign creation, event publishing, async workers with retries & dead-letter queues, structured logging, and Swagger docs for APIs.

Notifications You must be signed in to change notification settings

wak327/demo-multi-tenant-microservices

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

multi-tenant-microservices

Demo project showcasing a multi-tenant, event-driven microservice architecture with FastAPI, Celery, RabbitMQ, and PostgreSQL. The stack models a typical SaaS scenario with tenant-scoped authentication, campaign creation, and asynchronous campaign execution handled by a Celery worker.

Services

  • User Service (user-service): FastAPI API exposing user registration and JWT-based login scoped by tenant_id.
  • Campaign Service (campaign-service): FastAPI API for creating and listing campaigns per tenant. Publishes campaign.created events to RabbitMQ via Celery.
  • Worker Service (worker): Celery worker consuming campaign.created events, simulates campaign execution, persists processing logs, supports retries, and leverages a dead-letter queue.
  • Infrastructure: PostgreSQL for persistence and RabbitMQ (with management UI) for messaging.

Each service emits structured JSON logs and exposes basic Prometheus metrics.

Database schema

All services share a single PostgreSQL instance while scoping records by tenant_id. Tables are created automatically at startup via SQLAlchemy metadata.

users (managed by user-service)

Column Type Constraints/Notes
id SERIAL Primary key, auto-increment
tenant_id VARCHAR(64) Required, indexed
email VARCHAR(255) Required, indexed
hashed_password VARCHAR(255) Required, bcrypt hash of the submitted password
created_at TIMESTAMP Defaults to NOW()

Additional constraints: unique composite index on (tenant_id, email).

campaigns (managed by campaign-service)

Column Type Constraints/Notes
id SERIAL Primary key, auto-increment
tenant_id VARCHAR(64) Required, indexed
name VARCHAR(255) Required
description TEXT Optional
created_at TIMESTAMP Defaults to NOW()

campaign_task_logs (managed by worker)

Column Type Constraints/Notes
id SERIAL Primary key, auto-increment
campaign_id INTEGER Required, references originating campaign identifier
tenant_id VARCHAR(64) Required, indexed
status VARCHAR(32) Values: success, retry, or failed
payload JSON Raw event payload processed by the worker
attempts INTEGER Number of attempts recorded for this job
last_error TEXT Optional error details captured on failure
processed_at TIMESTAMP Defaults to NOW() when the worker logs the processing step

Running the stack

docker-compose build
docker-compose up

Services become available on:

Tip: add -d to docker-compose up to run in detached mode.

Sample workflow

  1. Register a tenant user

    curl -X POST http://localhost:8000/register \
      -H "Content-Type: application/json" \
      -d '{"tenant_id":"tenant-123","email":"[email protected]","password":"secret123"}'
  2. Login to get a JWT

    TOKEN=$(curl -s -X POST http://localhost:8000/login \
      -H "Content-Type: application/json" \
      -d '{"tenant_id":"tenant-123","email":"[email protected]","password":"secret123"}' | jq -r '.access_token')
  3. Create a campaign (publishes campaign.created event)

    curl -X POST http://localhost:8001/campaigns \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $TOKEN" \
      -d '{"name":"Tenant launch","description":"Welcome campaign"}'
  4. List campaigns for the tenant

    curl -H "Authorization: Bearer $TOKEN" http://localhost:8001/campaigns
  5. Inspect worker logs

    docker-compose logs -f worker

Metrics & Observability

  • Access /metrics on each FastAPI service for Prometheus-compatible metrics (e.g., http://localhost:8000/metrics). Worker metrics are exposed on port 9000 via the built-in Prometheus client server.
  • Logs are emitted in structured JSON for easier ingestion into log aggregation systems.

Dead-letter queue testing

To observe retry and DLQ handling, you can temporarily stop the worker and create campaigns. When the worker restarts, Celery will process backlogged messages. Exceeding retry counts will route events to the campaign.deadletter queue, visible in the RabbitMQ management UI.

Development notes

  • Requirements for each service live alongside the service code under */requirements.txt.
  • Database tables are created automatically on service start using SQLAlchemy metadata.
  • Adjust environment variables in docker-compose.yml to use stronger JWT secrets or separate databases per service.

About

A demo project showcasing multi-tenant microservices with FastAPI, PostgreSQL, RabbitMQ, Celery, and Docker. Includes user authentication, campaign creation, event publishing, async workers with retries & dead-letter queues, structured logging, and Swagger docs for APIs.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published