Skip to content

Refactor database connection handling to reduce memory usage and improve efficiency#101

Open
FelipePegado wants to merge 10 commits into
ccall48:masterfrom
FelipePegado:fix-memory-leaks
Open

Refactor database connection handling to reduce memory usage and improve efficiency#101
FelipePegado wants to merge 10 commits into
ccall48:masterfrom
FelipePegado:fix-memory-leaks

Conversation

@FelipePegado
Copy link
Copy Markdown

@FelipePegado FelipePegado commented May 10, 2026

Fix #100

I will let this application run for a while and monitor the memory usage to see if it remains stable.

Felipe added 2 commits May 9, 2026 22:58
Use contextlib.closing to ensure psycopg2 connections are closed
immediately after use instead of relying on GC. Add try/finally to
async_db_fetch and async_db_transaction so asyncpg pools are always
closed even when exceptions occur. Add explicit con.commit() for
write operations to preserve transactional semantics.
@FelipePegado FelipePegado marked this pull request as draft May 10, 2026 02:33
@FelipePegado FelipePegado marked this pull request as ready for review May 10, 2026 23:00
@ccall48
Copy link
Copy Markdown
Owner

ccall48 commented May 11, 2026

Hey mate, thanks for taking the time to submit this pr.

I'll have a look at this, using the context manager is the correct way to ensure and roll back transactions if something goes wrong. force closing the connection and clean up on the pool will cause its own issues.

i think the correct course of action would be to create a database pool every connection acquires a connection to and releases from as well as having all code async.

In this instance it does get a bit messy as I have mixed static and async code around and the connectors for each which is not ideal.

a quick run down if you're interested.

  • on project start, init/create a postgres db pool connection.
  • acquire and release connections to db only from this pool for each transaction.
  • work on moving all sync code over to be async.

@FelipePegado
Copy link
Copy Markdown
Author

Thanks for the feedback. Yeah, I agree that the right long-term fix is a single shared pool created at startup with fully async DB access. But since that would be a larger architectural change that we hadn’t discussed yet, I kept this PR focused on fixing the leak. I’ll work on the broader refactor this weekend, then.

@FelipePegado FelipePegado marked this pull request as draft May 16, 2026 18:59
Felipe added 7 commits May 16, 2026 16:04
Database now takes a DSN and creates the pool once (connect) / closes
it once (close), instead of being instantiated per call.
db_transaction/db_fetch/fetch_active_devices/create_tables are now
async and acquire connections from the shared pool. __init__ takes a
pool instead of the postgres_* params.
db_transaction/db_fetch/stream_meta/meta_up are now async over the
shared pool and redis.asyncio. Sync usage publishers run via
run_in_executor. stream_meta's try/except now wraps the loop body so a transient error no longer kills the stream permanently.
Replaces the ThreadPoolExecutor (one event loop pe0r thread) with a
single asyncio.run(main()) that creates one shared pool and runs all
five tasks via asyncio.gather. Periodic tasks use an async
run_periodically helper instead of asyncio.run per tick. build_dsn
now applies POSTGRES_SSL_MODE correctly (the old check compared a
single char and never matched).
create_pool defaults to min_size=10/max_size=10, so the service held
10 Postgres connections open for its whole lifetime. On a database
shared with ChirpStack that can push it past max_connections. Cap the
pool at max_size=5 and min_size=1 so idle connections are released.
@FelipePegado FelipePegado marked this pull request as ready for review May 17, 2026 17:08
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.

Memory leaks in database connection handling

2 participants