Skip to content

PostgreSQL connection pooling for WriterPostgres and ReaderPostgres #115

@oto-macenauer-absa

Description

@oto-macenauer-absa

Feature Description

Introduce connection pooling for both WriterPostgres (src/writers/writer_postgres.py) and ReaderPostgres (src/readers/reader_postgres.py) so that a new TCP connection to PostgreSQL is not opened on every write or read call.

Problem / Opportunity

Both WriterPostgres and ReaderPostgres currently call psycopg2.connect() on every invocation, opening and tearing down a full TCP connection each time. Under any sustained load — particularly for the new POST /stats/{topic_name} read endpoint which is expected to serve dashboard-style traffic — this will rapidly exhaust Postgres max_connections. Lambda warm instances reuse the handler/writer/reader objects across invocations, so a persistent or pooled connection can be maintained at the instance level.

Acceptance Criteria

  • WriterPostgres reuses a single connection (or draws from a pool) across warm-Lambda invocations instead of calling psycopg2.connect() per write.
  • ReaderPostgres does the same for read_stats() calls.
  • Stale/broken connections are detected and re-established automatically (e.g. via connection.closed check or a ping before use).
  • No real PostgreSQL calls are made in unit tests — existing mock patterns in conftest.py continue to work unchanged.
  • Integration tests pass with pooled connections.
  • All quality gates pass (./ci_local.sh).

Proposed Solution

Use psycopg2.pool.SimpleConnectionPool (min=1, max=1 for Lambda single-threaded execution) lazily initialised on the writer/reader instance. Before each operation, acquire a connection from the pool, return it after use. On OperationalError (broken pipe, server restart), discard the pool and reinitialise.

Alternatively, store a single lazy connection on the instance and check connection.closed before each use — simpler but less future-proof if threading assumptions change.

A pg_bouncer sidecar at the infrastructure layer is a valid complement but does not remove the need for application-level connection reuse within a warm Lambda instance.

Dependencies / Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions