(source: string, target: string)
| 1017 | // briefly lock the file). POSIX renames never hit this — retry with a short |
| 1018 | // backoff, forcing handle release first, instead of failing the whole migration. |
| 1019 | const renameWithRetry = async (source: string, target: string): Promise<void> => { |
| 1020 | // ~8s total. 1.9s was not enough on Windows: libSQL's native handle and |
| 1021 | // antivirus scans hold the freshly-written db past close() (observed as an |
| 1022 | // EBUSY boot crash in the v1.5.8 publish smoke run). |
| 1023 | const delaysMs = [50, 100, 250, 500, 1000, 2000, 4000]; |
| 1024 | for (let attempt = 0; ; attempt++) { |
| 1025 | try { |
| 1026 | fs.renameSync(source, target); |
| 1027 | return; |
| 1028 | } catch (cause) { |
| 1029 | const code = (cause as NodeJS.ErrnoException).code; |
| 1030 | if ((code !== "EBUSY" && code !== "EPERM") || attempt >= delaysMs.length) throw cause; |
| 1031 | nudgeNativeHandleRelease(); |
| 1032 | await new Promise((resolveDelay) => setTimeout(resolveDelay, delaysMs[attempt])); |
| 1033 | } |
| 1034 | } |
| 1035 | }; |
| 1036 | |
| 1037 | // Same lingering-handle window as renameWithRetry: on Windows a libSQL file's |
| 1038 | // native handle (and antivirus locks) can briefly outlive close(), so removing |
no test coverage detected