Skip to content

Fix SQLite concurrency risk in create_or_get method - #8

Closed
krishna3554 wants to merge 3 commits into
mainfrom
agent/add-memory-evaluation-benchmark
Closed

krishna3554 wants to merge 3 commits into
mainfrom
agent/add-memory-evaluation-benchmark

Conversation

@krishna3554

@krishna3554 krishna3554 commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Addresses SQLite locking issues that could cause data corruption under concurrent multi-tenant writes.\n\n- Added retry logic with exponential backoff for 'database is locked' errors in create_or_get\n- Improves data integrity under concurrent load from multiple tenants\n\nFixes issue identified during code review for scalability before beta release.


Open in Devin Review

Copilot AI lite review requested due to automatic review settings August 19, 2026 18:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View 1 additional finding in Devin Review.

Open in Devin Review

time.sleep(0.1 * (2 ** attempt))
continue
raise
raise RuntimeError("Unreachable code reached")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Leftover duplicated code block after the rewritten save routine breaks the memory service entirely

An old copy of the save logic was left behind after the new retry loop's final error (raise RuntimeError("Unreachable code reached") at services/dma-api/src/dma_api/repository.py:221) at a deeper indentation than the surrounding code, so the memory service can no longer start or store anything.
Impact: The API fails to load, so every request — remembering, recalling, listing, deleting — stops working.

Incomplete refactor leaves an orphaned, unreachable copy of the transaction body

The PR moved the body of create_or_get into a for attempt in range(max_retries) / try / with self._connect() block (lines 139-221), but the pre-existing body was not deleted. Lines 223-281 remain at 12-space indentation directly after the 8-space-indented raise RuntimeError(...) on line 221, with no enclosing block. This is an indentation/parse failure for the whole repository.py module, so dma_api.main (which imports SQLiteMemoryRepository, see services/dma-api/src/dma_api/main.py:69) cannot be imported. Even ignoring parsing, the block is dead code referencing an undefined connection.

Prompt for agents
In services/dma-api/src/dma_api/repository.py, the refactor of create_or_get into a retry loop (lines 139-221) duplicated the original method body: the old copy still exists at lines 223-281 at an indentation level that no longer belongs to any enclosing block, immediately after the `raise RuntimeError("Unreachable code reached")`. Remove the stale duplicated block so create_or_get contains only the new retry-wrapped implementation, and verify the module imports and the existing test suite passes.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +142 to +143
with self._connect() as connection:
connection.execute("BEGIN IMMEDIATE")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Failed write attempts leave database connections open, and repeated retries multiply the leak

Each attempt opens a new database connection that is never closed (with self._connect() as connection at services/dma-api/src/dma_api/repository.py:142), so retrying a locked write accumulates several open handles per request instead of one.
Impact: Under sustained concurrent writes the service can exhaust file handles and lock the database for longer, making writes fail more often.

sqlite3 connection context manager commits/rolls back but does not close

SQLiteMemoryRepository._connect (services/dma-api/src/dma_api/repository.py:403-407) returns a raw sqlite3.Connection. Using it as a context manager only manages the transaction — on exit it commits or rolls back but leaves the connection (and its file lock, until garbage collection) open. Previously one connection leaked per call; with the new loop up to max_retries connections leak per call, and the leaked connection from a failed attempt may still hold a reserved lock while the next attempt runs BEGIN IMMEDIATE, which can make the retry itself hit "database is locked". Wrapping with contextlib.closing(...) (or a try/finally close) fixes it.

Prompt for agents
services/dma-api/src/dma_api/repository.py:_connect returns a bare sqlite3.Connection and all call sites use `with self._connect() as connection`, which manages the transaction but never closes the connection. The new retry loop in create_or_get makes this worse because a failed attempt's connection stays open (potentially still holding locks) while the next attempt begins. Consider making _connect a contextmanager that closes the connection on exit (or wrap with contextlib.closing at each call site), and confirm the retry path releases resources between attempts.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 69522744ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread services/dma-api/src/dma_api/repository.py
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
project-49zal Ready Ready Preview Aug 28, 2026 5:58pm

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.

2 participants