A Jedi-approved SQLite connection pool with WAL, retries, and multi-thread/process safety.
Project description
sql3-lite-saver
A Jedi-approved SQLite connection pool, strong in the WAL side of the Force.
We make your Bad Batch good.
Why You Need a Connection Pool
SQLite is fast and embedded, but it isn't built for many simultaneous writers.
Without pooling, each connection must reinitialize SQLite state, and you'll quickly see:
sqlite3.OperationalError: database is locked
sql3-lite-saver helps by:
- Reusing a fixed number of open connections
- Enabling WAL (Write-Ahead Logging) automatically
- Retrying transparently with exponential backoff (optional Tenacity support)
- Supporting multi-threaded and multi-process workloads safely
⚠️ IMPORTANT: WAL Checkpoint Maintenance
If you use WAL mode (enabled by default), you MUST run periodic checkpoints or your database files can bloat over time.
Without checkpoints:
- WAL file can grow unbounded
- Read performance can steadily degrade
See the WAL Checkpoint Management section below for details.
Installation
From PyPI
pip install sql3-lite-saver
With optional retry engine (Tenacity)
pip install sql3-lite-saver[retry]
For development (editable)
pip install -e .[dev,retry]
Extras explained
| Extra | Purpose | What's Included |
|---|---|---|
retry |
Adds Tenacity for advanced retry control | tenacity>=8.0 |
dev |
Developer tools | ruff, pytest (optional), twine, build |
Example
from pathlib import Path
from sql3_lite_saver import ConnectionPool
pool = ConnectionPool(Path("app.db"), max_size=3)
with pool.acquire() as conn:
conn.execute("CREATE TABLE IF NOT EXISTS demo (id, msg)")
conn.execute("INSERT INTO demo VALUES (?, ?)", (1, "hello there"))
with pool.acquire() as conn:
print([dict(r) for r in conn.execute("SELECT * FROM demo").fetchall()])
Advanced Retry with Tenacity
When you install Tenacity (pip install sql3-lite-saver[retry]), sql3-lite-saver can use it for retry logic.
You can fine-tune retry behavior with parameters:
pool = ConnectionPool(
Path("app.db"),
enable_retry=True,
retry_attempts=8,
base_delay=0.5,
retry_jitter=0.25,
)
Without Tenacity installed, it falls back to built-in exponential backoff (1s, 2s, 4s, ... up to 60s).
WAL Checkpoint Management
Why Checkpoints Matter
When using WAL (Write-Ahead Logging), SQLite writes go to a separate file (app.db-wal) instead of the main database (app.db). Without regular checkpoints, the WAL file can grow indefinitely, causing:
- Disk space bloat - WAL can balloon to gigabytes
- Degraded read performance - SQLite may scan a larger WAL on reads
- File system issues - Very large WAL files can cause problems
Checkpoints transfer WAL data from app.db-wal back to the main app.db file, resetting the WAL.
Additional database files created by WAL mode:
app.db-wal- Write-Ahead Logapp.db-shm- Shared memory for coordination
Checkpoint Modes
from pathlib import Path
from sql3_lite_saver import ConnectionPool
pool = ConnectionPool(Path("app.db"))
# PASSIVE (default) - Non-blocking, checkpoint what you can
result = pool.checkpoint("PASSIVE")
# FULL - Checkpoint all frames, may block briefly
result = pool.checkpoint("FULL")
# RESTART - Like FULL, then reset WAL for reuse
result = pool.checkpoint("RESTART")
# TRUNCATE - Like RESTART, then shrink WAL to zero bytes (reclaim disk space)
result = pool.checkpoint("TRUNCATE")
print(result)
# {'busy': 0, 'log': 1024, 'checkpointed': 1024}
# busy=0 means full success, >0 means some pages couldn't be checkpointed
When to Checkpoint
- Periodic background task - Every hour with
PASSIVE(orTRUNCATEif you want to reclaim space) - Before backups - Use
TRUNCATEto minimize backup size - Low-traffic periods -
TRUNCATEduring maintenance windows - On application shutdown - Final
TRUNCATEto clean up
References
Testing
If you use pytest:
pytest -q
Or with the standard library unittest:
python -m unittest discover -s tests -v
Developer Shortcuts
make install-dev # editable install with dev + retry deps
make install-prod # editable install (minimal)
make lint # run Ruff
make test # run tests
make release # build + twine upload
License
MIT © 2025 @apresence
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sql3_lite_saver-0.99.1.tar.gz.
File metadata
- Download URL: sql3_lite_saver-0.99.1.tar.gz
- Upload date:
- Size: 13.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e16448ecd2dbafd614cddb6141f3c373f45f6c7f700b04b3a5d202a2fced5a7
|
|
| MD5 |
e2cbdfef092e267828a2f6a0d1b28d19
|
|
| BLAKE2b-256 |
e631703f22b288a9292ee53913e2961993ce5647982213bfa82742b1e693f446
|
Provenance
The following attestation bundles were made for sql3_lite_saver-0.99.1.tar.gz:
Publisher:
publish.yml on apresence/sql3-lite-saver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sql3_lite_saver-0.99.1.tar.gz -
Subject digest:
2e16448ecd2dbafd614cddb6141f3c373f45f6c7f700b04b3a5d202a2fced5a7 - Sigstore transparency entry: 928222641
- Sigstore integration time:
-
Permalink:
apresence/sql3-lite-saver@a863a640b5f45d6dab9898a8a905f500d106a5f9 -
Branch / Tag:
refs/tags/v0.99.1 - Owner: https://github.com/apresence
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a863a640b5f45d6dab9898a8a905f500d106a5f9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sql3_lite_saver-0.99.1-py3-none-any.whl.
File metadata
- Download URL: sql3_lite_saver-0.99.1-py3-none-any.whl
- Upload date:
- Size: 9.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2c47604ba5817c3545d2ef041c1d0f9b0e7b12c2b7b5a193a0b95ce64d08839
|
|
| MD5 |
bf818d5ccff5df7a1d2dc98086bb3539
|
|
| BLAKE2b-256 |
6ffe942afddd56822e71f09a67fe6d37b2da2a6d24056f4e3933f564f80c10d6
|
Provenance
The following attestation bundles were made for sql3_lite_saver-0.99.1-py3-none-any.whl:
Publisher:
publish.yml on apresence/sql3-lite-saver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sql3_lite_saver-0.99.1-py3-none-any.whl -
Subject digest:
d2c47604ba5817c3545d2ef041c1d0f9b0e7b12c2b7b5a193a0b95ce64d08839 - Sigstore transparency entry: 928222643
- Sigstore integration time:
-
Permalink:
apresence/sql3-lite-saver@a863a640b5f45d6dab9898a8a905f500d106a5f9 -
Branch / Tag:
refs/tags/v0.99.1 - Owner: https://github.com/apresence
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a863a640b5f45d6dab9898a8a905f500d106a5f9 -
Trigger Event:
push
-
Statement type: