(operation: () => Promise<T>, label: string)
| 139 | } |
| 140 | |
| 141 | async function withDatabaseLockRetry<T>(operation: () => Promise<T>, label: string): Promise<T> { |
| 142 | let lastError: unknown; |
| 143 | |
| 144 | for (let attempt = 1; attempt <= DB_LOCK_MAX_RETRIES; attempt++) { |
| 145 | try { |
| 146 | return await operation(); |
| 147 | } catch (error) { |
| 148 | lastError = error; |
| 149 | if (!isDatabaseLockedError(error) || attempt === DB_LOCK_MAX_RETRIES) { |
| 150 | throw error; |
| 151 | } |
| 152 | |
| 153 | const delay = DB_LOCK_RETRY_DELAY_MS * attempt; |
| 154 | console.warn( |
| 155 | `[SimpleSync] ${label} hit a locked database, retrying (${attempt}/${DB_LOCK_MAX_RETRIES}) in ${delay}ms...`, |
| 156 | ); |
| 157 | await sleep(delay); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | throw lastError instanceof Error ? lastError : new Error(String(lastError)); |
| 162 | } |
| 163 | |
| 164 | export interface TableChangeset { |
| 165 | records: Record<string, unknown>[]; |
no test coverage detected