Manages an embedded PostgreSQL server instance using pg0-embedded.
| 15 | |
| 16 | |
| 17 | class EmbeddedPostgres: |
| 18 | """Manages an embedded PostgreSQL server instance using pg0-embedded.""" |
| 19 | |
| 20 | def __init__( |
| 21 | self, |
| 22 | port: int | None = None, |
| 23 | username: str = DEFAULT_USERNAME, |
| 24 | password: str = DEFAULT_PASSWORD, |
| 25 | database: str = DEFAULT_DATABASE, |
| 26 | name: str = "hindsight", |
| 27 | config: dict[str, str] | None = None, |
| 28 | **kwargs, |
| 29 | ): |
| 30 | self.port = port # None means pg0 will auto-assign |
| 31 | self.username = username |
| 32 | self.password = password |
| 33 | self.database = database |
| 34 | self.name = name |
| 35 | # Extra postgresql.conf settings forwarded to Pg0 (e.g. ``max_connections``). |
| 36 | # Useful when tests spawn many xdist workers that each open a pool against |
| 37 | # the same pg0 instance — the postgres default of 100 max_connections is |
| 38 | # easy to exhaust under that fan-out. |
| 39 | self.config = config |
| 40 | self._pg0: Pg0 | None = None |
| 41 | |
| 42 | def _get_pg0(self) -> Pg0: |
| 43 | if self._pg0 is None: |
| 44 | try: |
| 45 | from pg0 import Pg0 |
| 46 | except ImportError: |
| 47 | raise ImportError( |
| 48 | "pg0-embedded is required for embedded PostgreSQL. " |
| 49 | "Install it with: pip install 'hindsight-api-slim[embedded-db]'" |
| 50 | ) |
| 51 | kwargs = { |
| 52 | "name": self.name, |
| 53 | "username": self.username, |
| 54 | "password": self.password, |
| 55 | "database": self.database, |
| 56 | } |
| 57 | # Only set port if explicitly specified |
| 58 | if self.port is not None: |
| 59 | kwargs["port"] = self.port |
| 60 | if self.config is not None: |
| 61 | kwargs["config"] = self.config |
| 62 | self._pg0 = Pg0(**kwargs) |
| 63 | return self._pg0 |
| 64 | |
| 65 | async def start(self, max_retries: int = 5, retry_delay: float = 4.0) -> str: |
| 66 | """Start the PostgreSQL server with retry logic.""" |
| 67 | port_info = f"port={self.port}" if self.port else "port=auto" |
| 68 | logger.info(f"Starting embedded PostgreSQL (name={self.name}, {port_info})...") |
| 69 | |
| 70 | pg0 = self._get_pg0() |
| 71 | last_error = None |
| 72 | |
| 73 | for attempt in range(1, max_retries + 1): |
| 74 | try: |
no outgoing calls