refactor(storage): route project DSNs and remove legacy backends
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import contextmanager
|
||||
from contextvars import ContextVar, Token
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterator
|
||||
|
||||
from psycopg.conninfo import make_conninfo
|
||||
|
||||
from app.core.config import get_pgconn_string, get_timescaledb_pgconn_string
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ActiveProjectRouting:
|
||||
project_code: str
|
||||
business_dsn: str
|
||||
timescale_dsn: str | None = None
|
||||
|
||||
|
||||
_active_project_routing: ContextVar[ActiveProjectRouting | None] = ContextVar(
|
||||
"active_project_routing",
|
||||
default=None,
|
||||
)
|
||||
|
||||
|
||||
def get_active_project_routing() -> ActiveProjectRouting | None:
|
||||
return _active_project_routing.get()
|
||||
|
||||
|
||||
@contextmanager
|
||||
def activate_project_routing(
|
||||
routing: ActiveProjectRouting,
|
||||
) -> Iterator[ActiveProjectRouting]:
|
||||
token: Token[ActiveProjectRouting | None] = _active_project_routing.set(routing)
|
||||
try:
|
||||
yield routing
|
||||
finally:
|
||||
_active_project_routing.reset(token)
|
||||
|
||||
|
||||
def _dsn_for_database(dsn: str, database_name: str) -> str:
|
||||
return make_conninfo(dsn, dbname=database_name)
|
||||
|
||||
|
||||
def get_project_pgconn_string(db_name: str | None = None) -> str:
|
||||
routing = get_active_project_routing()
|
||||
if routing is None:
|
||||
return get_pgconn_string(db_name=db_name)
|
||||
if db_name is None or db_name == routing.project_code:
|
||||
return routing.business_dsn
|
||||
return _dsn_for_database(routing.business_dsn, db_name)
|
||||
|
||||
|
||||
def get_project_timescale_pgconn_string(db_name: str | None = None) -> str:
|
||||
routing = get_active_project_routing()
|
||||
if routing is None:
|
||||
return get_timescaledb_pgconn_string(db_name=db_name)
|
||||
if routing.timescale_dsn is None:
|
||||
raise RuntimeError(
|
||||
f"TimescaleDB routing is not configured for project {routing.project_code}"
|
||||
)
|
||||
# Legacy simulation code used to derive the Timescale database name from
|
||||
# the project code. Project-scoped requests must instead use the complete
|
||||
# iot_data DSN selected by metadata routing.
|
||||
return routing.timescale_dsn
|
||||
Reference in New Issue
Block a user