Skip to content

Multi-Tenancy

Complete tenant isolation with per-tenant configurations, data segregation, and resource controls.

Architecture

graph TB
    subgraph "Shared Layer"
        A[Load Balancer]
        B[API Gateway]
    end

    subgraph "Tenant A"
        C[Router Instance A]
        D[Config A]
        E[(Database A)]
        F[Cache A]
    end

    subgraph "Tenant B"
        G[Router Instance B]
        H[Config B]
        I[(Database B)]
        J[Cache B]
    end

    subgraph "Tenant C"
        K[Router Instance C]
        L[Config C]
        M[(Database C)]
        N[Cache C]
    end

    A --> B
    B --> C
    B --> G
    B --> K
    C --> D
    C --> E
    C --> F
    G --> H
    G --> I
    G --> J
    K --> L
    K --> M
    K --> N

Tenant Isolation Levels

Level 1: Logical Isolation (Standard)

  • Shared infrastructure
  • Database-level separation
  • Row-level security
  • Namespace isolation

Level 2: Process Isolation (Premium)

  • Dedicated process per tenant
  • Separate caches
  • Independent configurations
  • Resource quotas enforced

Level 3: Physical Isolation (Platinum)

  • Dedicated infrastructure
  • Separate databases
  • Isolated networks
  • Custom deployments

Configuration

Tenant Creation

from stratarouter.enterprise.tenancy import TenantManager

manager = TenantManager()

# Create new tenant
tenant = manager.create_tenant(
    id="acme-corp",
    name="Acme Corporation",
    plan="premium",
    isolation_level="process",
    config={
        "max_routes": 1000,
        "max_requests_per_day": 1000000,
        "budget_limit": 10000.00,
        "data_residency": "us-east-1",
        "retention_days": 90
    }
)

# Configure tenant-specific settings
tenant.configure(
    router_config={
        "dimension": 384,
        "threshold": 0.5,
        "cache_enabled": True
    },
    security={
        "mfa_required": True,
        "ip_allowlist": ["203.0.113.0/24"],
        "session_timeout": 3600
    }
)

Tenant Context

from stratarouter.enterprise.tenancy import TenantContext

# Execute in tenant context
with TenantContext(tenant_id="acme-corp"):
    # All operations scoped to this tenant
    router = Router()
    result = router.route(query, embedding)

    # Data automatically isolated
    metrics = get_metrics()  # Only acme-corp's metrics

Data Segregation

Database Isolation

# Multi-tenant database configuration
database:
  strategy: database_per_tenant

  tenants:
    acme-corp:
      host: db1.example.com
      database: stratarouter_acme
      credentials: /secrets/acme-db

    globex:
      host: db2.example.com
      database: stratarouter_globex
      credentials: /secrets/globex-db

Row-Level Security

-- PostgreSQL RLS policies
CREATE POLICY tenant_isolation ON routes
  FOR ALL
  TO authenticated
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY tenant_isolation ON executions
  FOR ALL
  TO authenticated
  USING (tenant_id = current_setting('app.tenant_id')::uuid);

Cache Isolation

from stratarouter.enterprise.tenancy import TenantCache

cache = TenantCache()

# Keys automatically prefixed with tenant ID
cache.set("routes", routes)  # Actually stores "acme-corp:routes"
cache.get("routes")          # Only returns acme-corp's data

Resource Management

Quotas and Limits

from stratarouter.enterprise.tenancy import ResourceQuota

quota = ResourceQuota(
    tenant_id="acme-corp",
    limits={
        # Request limits
        "max_requests_per_second": 100,
        "max_requests_per_day": 1000000,

        # Resource limits
        "max_routes": 1000,
        "max_embeddings": 1000000,
        "max_storage_gb": 100,

        # Cost limits
        "daily_budget": 500.00,
        "monthly_budget": 10000.00,

        # Concurrency limits
        "max_concurrent_requests": 50,
        "max_batch_size": 32
    }
)

# Check quota before execution
if quota.check("max_requests_per_second"):
    execute_route()
else:
    raise QuotaExceededException()

Resource Tracking

from stratarouter.enterprise.tenancy import ResourceTracker

tracker = ResourceTracker()

# Track resource usage
tracker.record(
    tenant_id="acme-corp",
    resource_type="requests",
    amount=1,
    cost=0.001,
    metadata={"route_id": "billing"}
)

# Get usage report
usage = tracker.get_usage(
    tenant_id="acme-corp",
    period="2026-01",
    group_by=["resource_type", "route_id"]
)

# Usage summary
print(f"Requests: {usage.total_requests}")
print(f"Cost: ${usage.total_cost:.2f}")
print(f"Quota used: {usage.quota_percentage:.1f}%")

Cost Management

Chargeback

from stratarouter.enterprise.tenancy import Chargeback

chargeback = Chargeback()

# Generate invoice
invoice = chargeback.generate_invoice(
    tenant_id="acme-corp",
    period="2026-01",
    items=[
        {
            "description": "API Requests",
            "quantity": 1000000,
            "unit_price": 0.001,
            "amount": 1000.00
        },
        {
            "description": "Storage",
            "quantity": 50,  # GB
            "unit_price": 0.10,
            "amount": 5.00
        },
        {
            "description": "Support (Premium)",
            "quantity": 1,
            "unit_price": 5000.00,
            "amount": 5000.00
        }
    ],
    total=6005.00
)

# Export invoice
invoice.export("pdf", "invoices/acme-2026-01.pdf")

Showback

# Cost allocation without charging
showback = chargeback.generate_showback(
    tenant_id="acme-corp",
    period="2026-01",
    breakdown={
        "by_route": True,
        "by_user": True,
        "by_department": True
    }
)

# Show cost breakdown
print("Route costs:")
for route, cost in showback.by_route.items():
    print(f"  {route}: ${cost:.2f}")

Tenant Management

Tenant Lifecycle

from stratarouter.enterprise.tenancy import TenantLifecycle

lifecycle = TenantLifecycle()

# Onboard new tenant
await lifecycle.onboard(
    tenant_id="acme-corp",
    steps=[
        "create_database",
        "provision_infrastructure",
        "configure_security",
        "load_initial_data",
        "configure_integrations",
        "verify_setup"
    ]
)

# Suspend tenant (non-payment, security)
await lifecycle.suspend(
    tenant_id="acme-corp",
    reason="payment_overdue",
    preserve_data=True
)

# Resume tenant
await lifecycle.resume(tenant_id="acme-corp")

# Offboard tenant
await lifecycle.offboard(
    tenant_id="acme-corp",
    data_retention_days=30,
    export_data=True
)

Tenant Migration

# Migrate tenant to new infrastructure
migration = lifecycle.migrate_tenant(
    tenant_id="acme-corp",
    from_region="us-east-1",
    to_region="eu-west-1",
    strategy="blue_green",
    steps=[
        "replicate_database",
        "sync_cache",
        "update_dns",
        "verify_connectivity",
        "cutover",
        "cleanup_old"
    ]
)

# Monitor migration
status = migration.status()
print(f"Progress: {status.progress}%")

Custom Configurations

Per-Tenant Routing

# Tenant-specific routing configuration
tenant_configs = {
    "acme-corp": {
        "encoder": "openai-ada-002",
        "threshold": 0.5,
        "fallback_route": "general"
    },
    "globex": {
        "encoder": "custom-medical",
        "threshold": 0.7,
        "fallback_route": "escalation"
    }
}

# Apply tenant config
router = Router(**tenant_configs[tenant_id])

Tenant-Specific Integrations

# Configure integrations per tenant
integrations = {
    "acme-corp": {
        "providers": ["openai", "anthropic"],
        "cache_backend": "redis",
        "audit_backend": "splunk"
    },
    "globex": {
        "providers": ["azure-openai", "google"],
        "cache_backend": "memcached",
        "audit_backend": "elasticsearch"
    }
}

Security

Tenant Isolation Verification

from stratarouter.enterprise.tenancy import IsolationVerifier

verifier = IsolationVerifier()

# Verify tenant isolation
report = verifier.verify(
    tenant_id="acme-corp",
    checks=[
        "database_isolation",
        "cache_isolation",
        "network_isolation",
        "process_isolation",
        "resource_isolation"
    ]
)

if not report.all_passed:
    logger.critical(f"Isolation violation: {report.failures}")
    alert_security_team(report)

Cross-Tenant Access Prevention

# Middleware to enforce tenant context
from stratarouter.enterprise.tenancy import TenantMiddleware

@TenantMiddleware.enforce
async def execute_route(route_id: str):
    """Can only access current tenant's routes."""
    route = Route.get(route_id)  # Automatically filtered by tenant
    return await execute(route)

Monitoring

Per-Tenant Metrics

from stratarouter.enterprise.tenancy import TenantMetrics

metrics = TenantMetrics()

# Record tenant metrics
metrics.record(
    tenant_id="acme-corp",
    metric="requests_total",
    value=1,
    labels={"route": "billing", "status": "success"}
)

# Query tenant metrics
dashboard = metrics.get_dashboard(
    tenant_id="acme-corp",
    period="last_30_days",
    metrics=[
        "requests_total",
        "latency_p99",
        "error_rate",
        "cost_total"
    ]
)

Tenant Health

# Monitor tenant health
health = metrics.get_health(tenant_id="acme-corp")

print(f"Status: {health.status}")  # healthy, degraded, critical
print(f"Uptime: {health.uptime}%")
print(f"Error rate: {health.error_rate}%")
print(f"Quota usage: {health.quota_usage}%")

Best Practices

  1. Complete Isolation - Use database-per-tenant for sensitive data
  2. Resource Limits - Enforce quotas to prevent noisy neighbors
  3. Monitoring - Track per-tenant metrics and health
  4. Cost Transparency - Provide clear cost breakdowns
  5. Security First - Regular isolation audits
  6. Graceful Degradation - Handle quota exceeded gracefully
  7. Data Residency - Respect data sovereignty requirements

Next Steps


Secure multi-tenancy at scale. 🏢