Fastapi Middleware für Postgres Multi-Mieter-Schema-Schema verursacht Rennbedingungen mit gleichzeitigen AnfragenPython

Python-Programme
Guest
 Fastapi Middleware für Postgres Multi-Mieter-Schema-Schema verursacht Rennbedingungen mit gleichzeitigen Anfragen

Post by Guest »

Ich erstelle eine Multi-Mieter-Fastapi-Anwendung, die PostgreSQL-Schemas verwendet, um Mieterdaten zu trennen. Ich habe eine Middleware, die einen X-Tenant-ID -Header extrahiert, das Schema des Mieters nachgibt und dann das aktuelle Schema für die Datenbanksitzung entsprechend umschaltet. Für eine einzige Anfrage (über Postman) funktioniert die Middleware einwandfrei. Wenn ich jedoch mehrere Anfragen gleichzeitig sende, erhalte ich manchmal Fehler wie: < /p>
  • undefinierte Tabelle < /strong> < /li>
    Tabellenbeziehung nicht gefunden
Es scheint, dass die DB -Verbindung vorzeitig schließt oder zu früh zum öffentlichen Schema zurückkehrt , so werden mieterspezifische Tabellen nicht gefunden.

Code: Select all

SchemaSwitchMiddleware
)
from typing import Optional, Callable
from fastapi import Request, Response
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from app.db.session import SessionLocal, switch_schema
from app.repositories.tenant_repository import TenantRepository
from app.core.logger import logger
from contextvars import ContextVar

current_schema: ContextVar[str] = ContextVar("current_schema", default="public")

class SchemaSwitchMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next: Callable) -> Response:
"""
Middleware to dynamically switch the schema based on the `X-Tenant-ID` header.
If no header is present, defaults to `public` schema.
"""
db = SessionLocal() # Create a session here
try:
tenant_id: Optional[str] = request.headers.get("X-Tenant-ID")

if tenant_id:
try:
tenant_repo = TenantRepository(db)
tenant = tenant_repo.get_tenant_by_id(tenant_id)

if tenant:
schema_name = tenant.schema_name
else:
logger.warning("Invalid Tenant ID received in request headers")
return JSONResponse(
{"detail": "Invalid access"},
status_code=400
)
except Exception as e:
logger.error(f"Error fetching tenant: {e}. Defaulting to public schema.")
db.rollback()
schema_name = "public"
else:
schema_name = "public"

current_schema.set(schema_name)
switch_schema(db, schema_name)
request.state.db = db # Store the session in request state

response = await call_next(request)
return response

except Exception as e:
logger.error(f"SchemaSwitchMiddleware error: {str(e)}")
db.rollback()
return JSONResponse({"detail": "Internal Server Error"}, status_code=500)

finally:
switch_schema(db, "public") # Always revert to public
db.close()

< /code>

Datenbanksitzung (app /db /session.py) < /h2>
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker, declarative_base, Session
from app.core.logger import logger
from app.core.config import settings

# Base for models
Base = declarative_base()

DATABASE_URL = settings.DATABASE_URL

# SQLAlchemy engine
engine = create_engine(
DATABASE_URL,
pool_pre_ping=True,
pool_size=20,
max_overflow=30,
)

# Session factory
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def switch_schema(db: Session, schema_name: str):
"""Helper function to switch the search_path to the desired schema."""
db.execute(text(f"SET search_path TO {schema_name}"))
db.commit()
# logger.debug(f"Switched schema to: {schema_name}")

< /code>
Beispieltabellen < /h2>
öffentliches Schema: Enthält Tabellen wie Benutzer, Rollen, Mieter und User_lookup. < /p>
Mieterschema: Enthält Tabellen wie Benutzer, Rollen, Gebäude und Böden. Bei gleichzeitigen Anfragen kehrt die Umschaltung jedoch manchmal zu früh in das öffentliche Schema zurück, was zu Fehlern führt, da mieterspezifische Tabellen fehlen. >
[*] Was könnte die Rennbedingung verursachen, bei der das Schema der Verbindung bei gleichzeitigen Anfragen in die Öffentlichkeit umgestellt wird? < /li>
Wie kann ich sicherstellen Behält sein Mieterschema im gesamten Anforderungslebenszyklus ohne Störungen durch gleichzeitige Anfragen korrekt ein?
Gibt es einen besseren Ansatz (z. br /> < /ol>
Jede Hilfe auf dieser ist viel apriert. Danke

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post