Skip to content

fix(db): standardize SQLite pragmas across all connections#58

Open
serrrfirat wants to merge 1 commit into
mainfrom
implement-issue-claude-code
Open

fix(db): standardize SQLite pragmas across all connections#58
serrrfirat wants to merge 1 commit into
mainfrom
implement-issue-claude-code

Conversation

@serrrfirat

@serrrfirat serrrfirat commented Feb 21, 2026

Copy link
Copy Markdown
Owner

Summary

  • Centralize pragma configuration in getSynapseDb() (WAL mode, foreign keys, busy_timeout) so all connections to ~/.synapse/db.sqlite behave consistently
  • Deduplicate job-fsm.ts by reusing getSynapseDb() instead of manually creating a connection with duplicate pragma setup
  • Add busy_timeout to Screenpipe read-only connection to prevent spurious SQLITE_BUSY errors when Screenpipe is writing
  • Add pragmas to migration script for consistency during one-time migrations

Test plan

  • tsc --noEmit passes with zero errors
  • All 46 tests pass across 6 files (bun test)
  • Verify bun run src/index.ts doctor reports healthy DB
  • Verify bun run src/index.ts status shows no regressions

Closes #10

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Improved database connection reliability through timeout and concurrency configuration enhancements.
    • Optimized database initialization by centralizing instance management across the application.

getSynapseDb() now configures WAL mode, foreign keys, and busy_timeout,
eliminating inconsistent behavior between connections to the same DB file.
job-fsm.ts reuses getSynapseDb() instead of duplicating setup. Screenpipe
read-only connection gets busy_timeout to prevent spurious lock errors.

Closes #10

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @serrrfirat, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the robustness and consistency of SQLite database interactions by centralizing pragma configurations. It ensures that all connections to the main Synapse database adhere to a standardized set of settings, reducing potential concurrency issues and simplifying database management. Additionally, it addresses specific SQLITE_BUSY errors in the Screenpipe connection and streamlines the job state machine's database initialization.

Highlights

  • Centralized Pragma Configuration: Consolidated WAL mode, foreign keys, and busy_timeout settings within getSynapseDb() to ensure consistent behavior across all connections to ~/.synapse/db.sqlite.
  • Deduplicated job-fsm.ts: Refactored job-fsm.ts to reuse getSynapseDb(), eliminating redundant manual database connection and pragma setup.
  • Screenpipe busy_timeout: Added a busy_timeout pragma to the Screenpipe read-only connection to mitigate SQLITE_BUSY errors during concurrent write operations.
  • Migration Script Consistency: Incorporated necessary pragmas into the migration script for consistent database behavior during one-time migrations.
Changelog
  • src/db.ts
    • Added PRAGMA busy_timeout = 3000 to the Screenpipe database connection.
  • src/job-fsm.ts
    • Removed direct SQLite database initialization and pragma settings.
    • Replaced manual database setup with a call to getSynapseDb().
    • Removed unused imports related to homedir, initializeTables, and join.
  • src/scripts/migrate-to-fsm.ts
    • Added PRAGMA journal_mode = WAL and PRAGMA busy_timeout = 5000 to the migration script's database connection.
  • src/synapse-db.ts
    • Added PRAGMA journal_mode = WAL, PRAGMA foreign_keys = ON, and PRAGMA busy_timeout = 5000 to the getSynapseDb() function.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai

coderabbitai Bot commented Feb 21, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

The changes standardize SQLite PRAGMA configurations (WAL mode, foreign key enforcement, busy timeouts) across multiple database initialization entry points and consolidate job-fsm to use a shared database provider instead of creating a local instance.

Changes

Cohort / File(s) Summary
Database Configuration Standardization
src/synapse-db.ts, src/db.ts, src/scripts/migrate-to-fsm.ts
Added consistent PRAGMA settings across database initialization: WAL mode, foreign key enforcement, and busy timeouts (3–5 seconds) to ensure uniform concurrency handling and lock behavior.
Database Provider Consolidation
src/job-fsm.ts
Refactored to use shared getSynapseDb() instead of creating a local SQLite instance; removed local DB_PATH construction, SYNAPSE_DIR usage, and initializeTables call to rely on centralized database initialization.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit's tail of SQL care,
Pragmas aligned with thoughtful flair,
WAL and locks in harmony,
One database for all to see—
No more scattered, all now clear!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: standardizing SQLite pragmas across database connections to fix inconsistent configuration issues.
Linked Issues check ✅ Passed All code changes directly address issue #10 requirements: centralizing pragma configuration, ensuring consistency across DB entry points, and reducing SQLITE_BUSY errors through standardized timeouts.
Out of Scope Changes check ✅ Passed All modifications align with the linked issue scope: changes apply pragmas consistently across db.ts, job-fsm.ts, migrate-to-fsm.ts, and synapse-db.ts without introducing unrelated functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch implement-issue-claude-code

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request does a great job of centralizing and standardizing SQLite PRAGMA settings across different parts of the application, which improves consistency and maintainability. The changes in job-fsm.ts to use the shared getSynapseDb function are a good example of this. I've added a few comments with suggestions to further improve the implementation, including adding a missing pragma for consistency, and replacing magic numbers with constants.

Comment on lines +119 to +120
db.exec('PRAGMA journal_mode = WAL');
db.exec('PRAGMA busy_timeout = 5000');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

For consistency with getSynapseDb, you should also set PRAGMA foreign_keys = ON. Omitting it could lead to inconsistent database behavior, especially during a migration. You can also combine these into a single exec call for conciseness.

Suggested change
db.exec('PRAGMA journal_mode = WAL');
db.exec('PRAGMA busy_timeout = 5000');
db.exec('PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000;');

Comment thread src/db.ts
export function getScreenpipeDb(): Database {
return new Database(SCREENPIPE_DB_PATH, { readonly: true });
const db = new Database(SCREENPIPE_DB_PATH, { readonly: true });
db.exec('PRAGMA busy_timeout = 3000');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To avoid using a magic number, consider defining 3000 as a constant at the module level, for example: const BUSY_TIMEOUT_MS = 3000;. This improves readability and maintainability by making the value's purpose clear and centralizing its definition.

Comment thread src/synapse-db.ts
Comment on lines +19 to +21
db.exec('PRAGMA journal_mode = WAL');
db.exec('PRAGMA foreign_keys = ON');
db.exec('PRAGMA busy_timeout = 5000');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

You can combine these PRAGMA statements into a single exec call for conciseness. Additionally, consider defining 5000 as a constant to avoid a magic number, improving readability and maintainability.

Suggested change
db.exec('PRAGMA journal_mode = WAL');
db.exec('PRAGMA foreign_keys = ON');
db.exec('PRAGMA busy_timeout = 5000');
db.exec('PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000;');

@serrrfirat serrrfirat left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Summary
Clean, low-risk PR that correctly centralizes SQLite pragma configuration. The core changes are sound: getSynapseDb() now sets WAL mode, foreign keys, and busy_timeout in one place, and job-fsm.ts properly delegates to it instead of duplicating the setup. The busy_timeout addition to the Screenpipe read-only connection is a good defensive improvement. The only substantive finding is that the migration script doesn't fully align with the standardization goal (missing PRAGMA foreign_keys = ON), though this may be intentional. Overall, this is a well-scoped improvement with minimal risk.

console.log();

const db = new Database(DB_PATH);
db.exec('PRAGMA journal_mode = WAL');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The PR's stated goal is to standardize SQLite pragmas across all connections. The centralized getSynapseDb() sets journal_mode=WAL, foreign_keys=ON, and busy_timeout=5000. The migration script adds WAL and busy_timeout but omits foreign_keys=ON. This means FK constraints are not enforced during migration inserts — specifically, the INSERT INTO job_transitions with a job_id FK reference to jobs.id is not validated by SQLite. If lastInsertRowid returned an unexpected value, the orphaned transition row would not be caught. This may be intentional (to avoid ordering issues during migration), but it's inconsistent with the PR's purpose and undocumented.

Comment thread src/db.ts
export function getScreenpipeDb(): Database {
return new Database(SCREENPIPE_DB_PATH, { readonly: true });
const db = new Database(SCREENPIPE_DB_PATH, { readonly: true });
db.exec('PRAGMA busy_timeout = 3000');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The Screenpipe read-only connection uses busy_timeout=3000 (3s) while all Synapse DB connections use busy_timeout=5000 (5s). The difference is reasonable (read-only connections contending with Screenpipe writes need less patience than read-write connections contending with daemon concurrency), but the rationale is not documented anywhere. A future contributor might see the inconsistency and either 'fix' it incorrectly or be confused by it.

Comment thread src/synapse-db.ts
export function getSynapseDb(): Database {
ensureSynapseDir();
const db = new Database(SYNAPSE_DB_PATH);
db.exec('PRAGMA journal_mode = WAL');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

WAL mode is a persistent database property — once set, it survives connection close/reopen. Calling PRAGMA journal_mode = WAL on every getSynapseDb() invocation is harmless but redundant after the first call. Since getSynapseDb() is called ~30 times across index.ts and api-server.ts (each creating a new connection), this pragma is executed ~30 times unnecessarily per daemon lifetime. The overhead is negligible (SQLite returns early if already in WAL), but it's worth noting as a minor inefficiency. The foreign_keys and busy_timeout pragmas are per-connection and must be set every time — those are correct.

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.

standardize SQLite pragmas across all Synapse DB entry points

1 participant