| 143 | |
| 144 | @dataclass |
| 145 | class PgConnInfo: |
| 146 | user: str |
| 147 | host: str |
| 148 | port: int |
| 149 | database: str |
| 150 | password: str | None = None |
| 151 | ssl: bool = False |
| 152 | cluster: str | None = None |
| 153 | autocommit: bool = False |
| 154 | |
| 155 | def connect(self) -> psycopg.Connection: |
| 156 | conn = psycopg.connect( |
| 157 | host=self.host, |
| 158 | port=self.port, |
| 159 | user=self.user, |
| 160 | password=self.password, |
| 161 | dbname=self.database, |
| 162 | sslmode="require" if self.ssl else None, |
| 163 | ) |
| 164 | # Set SO_LINGER(1, 0) so close() sends RST instead of FIN, bypassing |
| 165 | # TIME_WAIT. Prevents exhausting the ~28k ephemeral port range under |
| 166 | # high connection churn (e.g. benchmarks doing rapid connect/disconnect). |
| 167 | self._set_linger(conn) |
| 168 | if self.autocommit: |
| 169 | conn.autocommit = True |
| 170 | if self.cluster: |
| 171 | with conn.cursor() as cur: |
| 172 | cur.execute(f"SET cluster = {self.cluster}".encode()) |
| 173 | return conn |
| 174 | |
| 175 | @staticmethod |
| 176 | def _set_linger(conn: psycopg.Connection) -> None: |
| 177 | import socket |
| 178 | import struct |
| 179 | |
| 180 | fd = conn.pgconn.socket |
| 181 | if fd < 0: |
| 182 | return |
| 183 | sock = socket.socket(fileno=fd) |
| 184 | try: |
| 185 | sock.setsockopt( |
| 186 | socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", 1, 0) |
| 187 | ) |
| 188 | finally: |
| 189 | sock.detach() |
| 190 | |
| 191 | def to_conn_string(self) -> str: |
| 192 | return ( |
| 193 | f"postgres://{quote(self.user)}:{quote(self.password)}@{self.host}:{self.port}/{quote(self.database)}" |
| 194 | if self.password |
| 195 | else f"postgres://{quote(self.user)}@{self.host}:{self.port}/{quote(self.database)}" |
| 196 | ) |
| 197 | |
| 198 | |
| 199 | def parse_pg_conn_string(conn_string: str) -> PgConnInfo: |
no outgoing calls
no test coverage detected