fix(test): prevent EBUSY on Windows from failing embedding-regression cleanup (#1353)#1356
Conversation
… cleanup
SQLite WAL checkpoint holds OS-level file locks for hundreds of ms after
db.close() returns on Windows. The plain rmSync in afterAll has no retry
budget and fails intermittently with EBUSY: resource busy or locked.
Three-part fix:
- Call flushDeferredClose() to close any pending deferred DB handles first
- Register process.once('exit') safety net so the temp dir is cleaned up
even if the immediate attempt is blocked by a WAL lock
- Wrap rmSync in try/catch with maxRetries:10/retryDelay:200 so a transient
EBUSY never propagates as a test failure (all assertions already passed)
Fixes #1353
Greptile SummaryThis PR fixes intermittent
Confidence Score: 5/5The change only touches test cleanup logic; all test assertions are unaffected and the new cleanup path is purely best-effort. The fix is narrowly scoped to afterAll cleanup. It correctly captures tmpDir before the primary delete attempt, re-throws non-EBUSY/EPERM errors, and uses force: true in the exit handler so a double-delete is a no-op. No test assertions or production code are touched. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[afterAll fires] --> B{tmpDir set?}
B -- No --> Z[return early]
B -- Yes --> C[flushDeferredClose]
C --> D[Register process.once exit handler\ncapturedDir = tmpDir]
D --> E[fs.rmSync with maxRetries:10\nretryDelay:200]
E -- success --> F[Directory deleted\nexit handler runs rmSync again\nforce:true = no-op on ENOENT]
E -- throws EBUSY or EPERM --> G[Swallow error\nexit handler is safety net]
E -- throws other error --> H[Re-throw — surfaces as test failure]
G --> I[process exit event fires]
I --> J[fs.rmSync capturedDir force:true]
J -- dir already gone --> K[No-op]
J -- dir still locked --> L[Catch bare — best-effort]
Reviews (11): Last reviewed commit: "Merge branch 'main' into fix/embedding-r..." | Re-trigger Greptile |
|
Added the |
Summary
flushDeferredClose()call before temp dir deletion to close any pending deferred DB handlesrmSyncwithmaxRetries: 10 / retryDelay: 200and catch remaining errors so a transient EBUSY lock never propagates as a test failure (all assertions already passed before cleanup)process.once('exit')as a safety net — temp dir is cleaned up at process exit if the WAL lock outlasts the retry budgetRoot cause
SQLite WAL mode on Windows holds OS-level file locks for hundreds of ms after
db.close()returns. The plainfs.rmSyncinafterAllhad no retry budget, so the lock ongraph.dbcaused intermittentEBUSY: resource busy or locked, unlinkfailures in CI even though all 2878 test assertions passed.Test plan
embedding-regression.test.tsFixes #1353