Implement transaction retry logic for SQLITE_BUSY (bd-ola6)

Add exponential backoff retry for BEGIN IMMEDIATE transactions to handle
concurrent write load without spurious failures.

Changes:
- Add IsBusyError() helper to detect database locked errors
- Add beginImmediateWithRetry() with exponential backoff (10ms, 20ms, 40ms, 80ms, 160ms)
- Update CreateIssue and CreateIssuesInBatch to use retry logic
- Add comprehensive tests for error detection and retry behavior
- Handles context cancellation between retry attempts
- Fails fast on non-busy errors

This eliminates spurious SQLITE_BUSY failures under normal concurrent usage
while maintaining proper error handling for other failure modes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-24 01:10:04 -08:00
parent a8919fde9f
commit 125d02860c
5 changed files with 256 additions and 76 deletions

View File

@@ -144,7 +144,8 @@ func (s *SQLiteStorage) CreateIssuesWithOptions(ctx context.Context, issues []*t
}
defer func() { _ = conn.Close() }()
if _, err := conn.ExecContext(ctx, "BEGIN IMMEDIATE"); err != nil {
// Use retry logic with exponential backoff to handle SQLITE_BUSY under concurrent load (bd-ola6)
if err := beginImmediateWithRetry(ctx, conn, 5, 10*time.Millisecond); err != nil {
return fmt.Errorf("failed to begin immediate transaction: %w", err)
}