Skip to content

feat: #401 background connection keep-alive for relational sink#448

Merged
Sadeequ merged 1 commit into
StellarFlow-Network:mainfrom
Fury03:issue-401-connection-keepalive
Jun 2, 2026
Merged

feat: #401 background connection keep-alive for relational sink#448
Sadeequ merged 1 commit into
StellarFlow-Network:mainfrom
Fury03:issue-401-connection-keepalive

Conversation

@Fury03

@Fury03 Fury03 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

feat: #401 background connection keep-alive for relational sink

Summary

Adds src/database/connection.py with a ConnectionKeepAlive class that runs a low-overhead background heartbeat (SELECT 1;) on a fixed interval (default 30s) to keep a long-lived relational connection warm during quiet, low-volume market windows.

Motivation

Closes #401. Serverless / autoscaled Postgres sinks and intermediary poolers (e.g. PgBouncer) commonly drop idle TCP connections after a short timeout. When the next price record arrives, the first write stalls waiting for a fresh TCP handshake and re-authentication. A periodic heartbeat keeps the channel active so the write path never pays the reconnect cost.

Implementation

ConnectionKeepAlive mirrors the conventions already in this directory: the threading idiom (daemon thread + lock + threading.Event) follows batch_sink.py, and the connection style follows the psycopg2/PostgreSQL usage in cleanup_job.py.

  • A daemon thread wakes every interval seconds and issues SELECT 1;.
  • stop() signals the thread via a threading.Event, so shutdown is prompt and does not wait out the full interval.
  • A failed ping is logged and swallowed (returns False) so a transient drop never kills the background loop — the next tick simply retries.
  • start() is idempotent; invalid arguments (None connection, non-positive interval) are rejected.

Note on the SQLite vs. Postgres mismatch

The keep-alive is written connection-agnostic: it accepts any DB-API 2.0 connection exposing cursor(). This is deliberate, because the database layer in this repo is currently inconsistent — cleanup_job.py uses psycopg2/PostgreSQL (where idle-connection drops are a real phenomenon and this heartbeat is meaningful), while models.py and batch_sink.py use sqlite3 (a local file with no socket to keep open, where the ping is harmless but inert). The class and its docstring make this explicit so the behaviour is meaningful for the networked sink the issue describes without misrepresenting what it does against SQLite.

Changes

  • src/database/connection.py (new): ConnectionKeepAlive class plus DEFAULT_PING_INTERVAL and HEARTBEAT_QUERY constants.
  • src/database/__init__.py (new): package marker so from database.connection import ... resolves (the directory previously had none, unlike src/analytics/).
  • tests/test_connection_keepalive.py (new): 7 mock-based unit tests.

Testing

7 new unit tests, all passing:

python3 -m pytest tests/test_connection_keepalive.py -v
# 7 passed

They cover: the heartbeat query is executed, failures are swallowed rather than raised, the background thread starts/stops cleanly, the loop pings on its interval, stop() returns promptly instead of blocking for the full interval, double-start() is a no-op, and invalid arguments are rejected. Tests use unittest.mock connections, consistent with the existing Python tests, so no live database is required.

Note: the full Python suite has two pre-existing failures unrelated to this change, reproducible on a clean checkout (verified by stashing these files): tests/test_window.py fails to import on Python 3.12 (Deque was removed from collections.abc), and tests/test_signer.py::TestExceptionPathCleanup::test_signing_error_does_not_abort_cleanup fails on a read-only-attribute mock. Neither touches the files in this PR.

@drips-wave

drips-wave Bot commented Jun 2, 2026

Copy link
Copy Markdown

@Fury03 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Sadeequ Sadeequ merged commit d579597 into StellarFlow-Network:main Jun 2, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🗄️ Database-Pipeline | Asynchronous Connection Keep-Alives for Serverless Relational Sinks

2 participants