Add concurrency protection for Fava/Beancount ledger writes #5
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/concurrency-protection"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
This PR addresses critical race conditions when multiple requests try to write to the Fava/Beancount ledger file simultaneously. Without these protections, concurrent writes can cause data loss, duplicate entries, or file corruption.
Fixes #4
Fix Implemented
The following concurrency protections have been implemented:
1. Global Write Lock in FavaClient
Added
asyncio.Lock()to serialize all write operations to the Fava/Beancount ledger:2. Protected Write Methods
The following methods now acquire the global write lock before modifying the ledger:
add_entry()- Wrapped withasync with self._write_lock:add_account()- Wrapped with lock + retry logic for checksum conflictsupdate_entry_source()- Wrapped with lockdelete_entry()- Wrapped with lock3. Retry Logic with Exponential Backoff
add_account()now implements optimistic concurrency control:ChecksumConflictErrorif all retries fail4. Idempotent Entry Creation
New
add_entry_idempotent()method:5. Per-User Locking
Added
get_user_lock(user_id)method for user-specific operations:6. Protected Invoice Payment Processing
Updated
on_invoice_paid()in tasks.py:add_entry_idempotent()with payment hash as idempotency keyFiles Changed
fava_client.py- Added locks, retry logic, idempotent methodtasks.py- Updatedon_invoice_paid()to use new protectionsWhat This Fixes
Test Plan
Limitations
🤖 Generated with Claude Code
Closing — this work landed directly on
mainoutside the PR UI.The PR head commit
b5c3650("Add concurrency protection for Fava/Beancount ledger writes") is reachable frommain. Verified locally:fava_client.pycontains_write_lock,_user_locks,get_user_lock(),add_entry_idempotent(), andChecksumConflictErrortasks.pyuses per-user locks and idempotent entry creation inon_invoice_paid()No further action needed.
Pull request closed