Resource Leak: DatabaseResourceHandler leaks SQLite connections from un-rolled-back checkpoints #8111

Open
opened 2026-04-13 03:34:33 +00:00 by HAL9000 · 1 comment
Owner

Metadata

  • Commit message: fix: close leaked sqlite3 connections in DatabaseResourceHandler checkpoint cleanup
  • Branch name: fix/database-resource-handler-sqlite-connection-leak
  • Module: src/cleveragents/resource/handlers/database.py
  • Class: DatabaseResourceHandler
  • Method: _create_checkpoint_sqlite
  • Lines: 881–902

Background and Context

The DatabaseResourceHandler provides a checkpointing mechanism for SQLite databases using SAVEPOINT. When create_checkpoint is called, the _create_checkpoint_sqlite method opens a new sqlite3.Connection, creates a savepoint, and stores the open connection in the self._sqlite_checkpoints dictionary. The expectation is that this connection will be closed later when rollback_to is called for that checkpoint.

If a checkpoint is created but a rollback never occurs for it (e.g., the plan completes successfully without needing to roll back), the sqlite3.Connection object associated with that checkpoint is never closed. It remains in the _sqlite_checkpoints dictionary for the lifetime of the handler instance, holding open a file handle and consuming memory. This constitutes a resource leak.

Expected Behavior

The DatabaseResourceHandler should provide a mechanism to clean up and close any open connections for checkpoints that are no longer needed. Specifically:

  • When a plan finishes (successfully or otherwise), all sqlite3.Connection objects stored in _sqlite_checkpoints for that plan should be explicitly closed and removed from the dictionary.
  • No open sqlite3.Connection handles should persist beyond the plan lifecycle.

Acceptance Criteria

  • A discard_checkpoints(plan_id: str) method (or equivalent) is added to DatabaseResourceHandler that closes all open sqlite3.Connection objects associated with the given plan_id and removes them from _sqlite_checkpoints.
  • The cleanup method is invoked at an appropriate point in the plan execution lifecycle (e.g., on plan completion or teardown), ensuring no connections are leaked on the happy path.
  • No sqlite3.Connection objects remain open after a plan finishes, regardless of whether a rollback occurred.
  • Existing checkpoint rollback behaviour is unaffected.
  • Unit tests cover the new cleanup method and verify connections are closed.

Subtasks

  • 1. Implement discard_checkpoints(plan_id: str) on DatabaseResourceHandler — iterate over checkpoints keyed to plan_id, call .close() on each connection, and delete the entries from _sqlite_checkpoints.
  • 2. Integrate the cleanup call into the plan execution lifecycle (identify the correct teardown hook or finally-block in the executor/runner).
  • 3. Add unit tests asserting that connections are closed after discard_checkpoints is called and that no leak occurs on the happy path.
  • 4. Review whether analogous leaks exist for other resource handler checkpoint implementations and file follow-up issues if needed.

Definition of Done

  • All subtasks above are checked off.
  • discard_checkpoints (or equivalent) is implemented, tested, and integrated into the plan lifecycle.
  • No sqlite3.Connection objects are leaked after plan completion.
  • All existing tests continue to pass (nox green).
  • The fix is merged into the master branch.

Automated by CleverAgents Bot
Agent: new-issue-creator

## Metadata - **Commit message:** `fix: close leaked sqlite3 connections in DatabaseResourceHandler checkpoint cleanup` - **Branch name:** `fix/database-resource-handler-sqlite-connection-leak` - **Module:** `src/cleveragents/resource/handlers/database.py` - **Class:** `DatabaseResourceHandler` - **Method:** `_create_checkpoint_sqlite` - **Lines:** 881–902 ## Background and Context The `DatabaseResourceHandler` provides a checkpointing mechanism for SQLite databases using `SAVEPOINT`. When `create_checkpoint` is called, the `_create_checkpoint_sqlite` method opens a new `sqlite3.Connection`, creates a savepoint, and stores the open connection in the `self._sqlite_checkpoints` dictionary. The expectation is that this connection will be closed later when `rollback_to` is called for that checkpoint. If a checkpoint is created but a rollback never occurs for it (e.g., the plan completes successfully without needing to roll back), the `sqlite3.Connection` object associated with that checkpoint is never closed. It remains in the `_sqlite_checkpoints` dictionary for the lifetime of the handler instance, holding open a file handle and consuming memory. This constitutes a resource leak. ## Expected Behavior The `DatabaseResourceHandler` should provide a mechanism to clean up and close any open connections for checkpoints that are no longer needed. Specifically: - When a plan finishes (successfully or otherwise), all `sqlite3.Connection` objects stored in `_sqlite_checkpoints` for that plan should be explicitly closed and removed from the dictionary. - No open `sqlite3.Connection` handles should persist beyond the plan lifecycle. ## Acceptance Criteria - [ ] A `discard_checkpoints(plan_id: str)` method (or equivalent) is added to `DatabaseResourceHandler` that closes all open `sqlite3.Connection` objects associated with the given `plan_id` and removes them from `_sqlite_checkpoints`. - [ ] The cleanup method is invoked at an appropriate point in the plan execution lifecycle (e.g., on plan completion or teardown), ensuring no connections are leaked on the happy path. - [ ] No `sqlite3.Connection` objects remain open after a plan finishes, regardless of whether a rollback occurred. - [ ] Existing checkpoint rollback behaviour is unaffected. - [ ] Unit tests cover the new cleanup method and verify connections are closed. ## Subtasks - [ ] 1. Implement `discard_checkpoints(plan_id: str)` on `DatabaseResourceHandler` — iterate over checkpoints keyed to `plan_id`, call `.close()` on each connection, and delete the entries from `_sqlite_checkpoints`. - [ ] 2. Integrate the cleanup call into the plan execution lifecycle (identify the correct teardown hook or finally-block in the executor/runner). - [ ] 3. Add unit tests asserting that connections are closed after `discard_checkpoints` is called and that no leak occurs on the happy path. - [ ] 4. Review whether analogous leaks exist for other resource handler checkpoint implementations and file follow-up issues if needed. ## Definition of Done - All subtasks above are checked off. - `discard_checkpoints` (or equivalent) is implemented, tested, and integrated into the plan lifecycle. - No `sqlite3.Connection` objects are leaked after plan completion. - All existing tests continue to pass (`nox` green). - The fix is merged into the `master` branch. --- **Automated by CleverAgents Bot** Agent: new-issue-creator
HAL9000 added this to the v3.4.0 milestone 2026-04-13 03:34:45 +00:00
Author
Owner

Verified — SQLite connection leaks from un-rolled-back checkpoints will accumulate. Should Have fix for v3.4.0. Verified.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

✅ **Verified** — SQLite connection leaks from un-rolled-back checkpoints will accumulate. **Should Have** fix for v3.4.0. Verified. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#8111
No description provided.