feat(store): non-blocking validateStoragePath async background init (Issue #795)#797
feat(store): non-blocking validateStoragePath async background init (Issue #795)#797jlin53882 wants to merge 3 commits into
Conversation
… init Adds async version of validateStoragePath (5 sync I/O → async: lstat/realpath/exists/mkdir/access). register() fires off the async validation in setImmediate() so it does not block the event loop during plugin registration. _sync _initPluginState still runs synchronously first so _singletonState is always set before hooks register. _Issue: CortexReach#795
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 930b3d4934
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // won't matter (plugin failed to start anyway). | ||
| const config = parsePluginConfig(api.pluginConfig); | ||
| const resolvedDbPath = api.resolvePath(config.dbPath || getDefaultDbPath()); | ||
| _startAsyncValidation(resolvedDbPath, api); |
There was a problem hiding this comment.
Remove sync validation from the registration path
When the first register() call runs, this background validation is immediately followed by _initPluginState(api) at line 2200, and _initPluginState still calls validateStoragePath(resolvedDbPath) at line 1963. That means the same lstatSync/realpathSync/existsSync/mkdirSync/accessSync calls still block plugin registration, and the new async path validation just runs a second time later. For the high-concurrency startup scenario this change is meant to fix, the blocking I/O remains on the critical path.
Useful? React with 👍 / 👎.
Add 5 tests for validateStoragePathAsync: - resolves absolute path unchanged - creates directory if it does not exist - rejects unwritable parent directory - resolves symlink to real path - returns resolved path for existing directory Register in ci-test-manifest.mjs under core-regression group.
|
Plugin init is getting blocked by sync I/O in our environment. This async fix would be really helpful. Looking forward to the merge! |
|
You can manually download this PR and apply it locally. After testing, it
has proven to be very effective in solving the problem.
OKmiao88888888 ***@***.***> 於 2026年5月11日 週一 上午11:38 寫道:
… *OKmiao88888888* left a comment (CortexReach/memory-lancedb-pro#797)
<#797 (comment)>
Plugin init is getting blocked by sync I/O in our environment. This async
fix would be really helpful. Looking forward to the merge!
—
Reply to this email directly, view it on GitHub
<#797 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ASID5C75X4KG5K6ELY4YQD342FDMLAVCNFSM6AAAAACYYNRGC2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DIMJXGQYTKNRTGU>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
Review finding: P1: async validation does not remove the sync startup I/O This PR starts Because the issue is specifically plugin init blocking on |
…critical path Replace the blocking sync validateStoragePath() call in _initPluginState with setImmediate + validateStoragePathAsync. The 5 sync I/O operations (lstatSync/realpathSync/existsSync/mkdirSync/accessSync) are now deferred to the next event loop tick so they no longer block plugin registration. This is the '方案 B' fix — truly replacing the sync call, not just adding an async version alongside it. Sync path validation failure logs a warning instead of throwing, matching the async behavior.
✅ P2 Fix Applied — Sync
|
| Test | Status |
|---|---|
npm test (28 existing tests) |
✅ 28/28 |
| validateStoragePathAsync — rejects when path is file | ✅ |
| validateStoragePathAsync — succeeds with existing directory | ✅ |
| validateStoragePathAsync — creates missing intermediate dirs recursively | ✅ |
| register() — returns within 5ms (no sync I/O) | ✅ |
| register() — does NOT throw with invalid path (validation deferred) | ✅ |
PR diff summary: +179/-2 across 4 files (index.ts, src/store.ts, test/validate-storage-path-async.test.mjs, scripts/ci-test-manifest.mjs)
|
Closing this PR for now. The startup performance issue is narrow, while this changes storage path validation from synchronous startup failure into deferred background warning behavior. That tradeoff needs stronger evidence and a safer design before merge. If we revisit this, please bring benchmarks and preserve clear startup failure semantics where possible. |
Summary
Issue: #795 — plugin init 時
validateStoragePath的 5 個 sync I/O (lstatSync,realpathSync,existsSync,mkdirSync,accessSync) block event loop,影響高併發 startup 效能。Fix (方案 B — 真正替換):移除
_initPluginState中的 syncvalidateStoragePath()呼叫,改用setImmediate+validateStoragePathAsync()。這樣 5 個 sync I/O 完全不在 critical path 上。Changes
src/store.ts(+74 行)pathExistsAsync(path: string): Promise<boolean>—fs/promises.access的 async 包裝validateStoragePathAsync(dbPath: string): Promise<string>— 完整 async 版本lstat→lstatrealpathSync→realpathmkdirSync→mkdir(recursive + 0o755)accessSync→accessvalidateStoragePath(sync 原版) 保留,給其他需要 sync 的 caller 用index.ts(+18/-2 行)validateStoragePathAsync_initPluginState內的validateStoragePath(resolvedDbPath)改為:為什麼不用
_startAsyncValidationwrapper:維護者指出 fire-and-forget 方案只是 additive,不是真正替換。方案 B 直接在_initPluginState內用setImmediate取代 sync 呼叫。Test Coverage
test/validate-storage-path-async.test.mjs— 5 個單元測試,全數通過:Maintenance Comment Response
已修復:
validateStoragePathsync 呼叫已從_initPluginState移除,替換為setImmediate(async () => { await validateStoragePathAsync(...) })。5 個 sync I/O 現在完全在 register() critical path 之外執行。