v3.3.97 (UV_THREADPOOL_SIZE 64→8) was a decisive win — mean event-loop-delay at 70 active uploads dropped 200ms→~11ms (18×), rss 577→287MB, renderer healthy in 14/15 windows. But the user reports it is still not perfectly smooth. A focused multi-agent investigation plus an adversarial review localized the residual to TWO distinct, separately-measured spike sources: 1. Read-bursts. In the tail windows the file-read histogram inverts: FSReqCallback climbs to 66-70 against threadpool=8 (~8.75× queue depth) while SimpleWriteWrap (socket writes) collapses to 4-24 and mean delay rises to 30-42ms. GC is ruled out (gcMax ≤27ms in every window). The clean inversion at a stable active=70 / pending=1287 shows the reads are causal, not a symptom of a block elsewhere. 2. A suspected synchronous config-persist stall. save() → load() reparses the whole electron-config.json — which now carries the 1287-job pending queue nested in globalSettings plus full history — on every persist (because _atomicWrite nulls the read cache), then _serializeForDisk JSON.stringify(…, null, 2) of all of it. One tail sample (max 1021ms, heap spiking to 142MB) fits a large synchronous structuredClone+stringify, but it is a single confounded point, so this build only INSTRUMENTS the path rather than asserting the cause. This release ships one behavioral change (kept to a single variable so the next log attributes cleanly) plus measurement: - highWaterMark 256KB→1MB in all five streaming read loops (lib/hosters.js, doodstream/voe/vidmoly CHUNK_SIZE consts, and the inline value in clouddrop-upload.js:108 — NOT the 16MB server chunk at clouddrop-upload.js:12). UV_THREADPOOL_SIZE stays 8. This deepens each stream's read-ahead cushion from ~0.43s to ~1.7s at the per-stream rate, so a stream tolerates the threadpool queue without starving its socket write, and cuts read-completion callbacks and per-chunk Buffer allocations ~4×. Byte-correctness is unaffected: Content-Length is preamble+fileSize+epilogue, independent of chunk size, and the chunk size never touches the multipart boundaries. Fully reversible; a dedicated read- concurrency semaphore is held in reserve if 1MB does not clear the bursts. - config-store.js now times load() (the full reparse, which the account-failed handler also hits per failure) and the _commit serialize, logging `config-load …` / `config-serialize wall=…ms bytes=… hist=… queue=…` when the synchronous work exceeds 20ms. load() is split into a timing wrapper + _loadImpl; the timer is a no-op until main.js wires configStore.setPerfLog → logInfo. The renderer batch-drain fix for the one observed 243ms longtask is intentionally deferred: that jank is downstream of the main-thread read-burst flooding IPC, so fix #1 should make it self-heal; bundling it would confound the measurement and touch the progress hot path. All 397 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
1.4 KiB
JSON
57 lines
1.4 KiB
JSON
{
|
|
"name": "multi-hoster-uploader",
|
|
"version": "3.3.98",
|
|
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
|
"main": "main.js",
|
|
"scripts": {
|
|
"start": "electron .",
|
|
"test": "node --test tests/*.test.js tests/ui-smoke.js",
|
|
"dist": "electron-builder --win",
|
|
"release:win": "electron-builder --publish never --win nsis portable",
|
|
"release:gitea": "node scripts/release_gitea.mjs"
|
|
},
|
|
"dependencies": {
|
|
"chokidar": "^3.6.0",
|
|
"undici": "^7.16.0",
|
|
"ws": "^8.19.0"
|
|
},
|
|
"devDependencies": {
|
|
"electron": "^41.3.0",
|
|
"electron-builder": "^26.8.1",
|
|
"eslint": "^10.1.0",
|
|
"eslint-plugin-security": "^4.0.0",
|
|
"rcedit": "^4.0.1"
|
|
},
|
|
"build": {
|
|
"appId": "com.multihoster.uploader",
|
|
"productName": "Multi-Hoster-Upload",
|
|
"directories": {
|
|
"buildResources": "assets",
|
|
"output": "release"
|
|
},
|
|
"files": [
|
|
"main.js",
|
|
"preload.js",
|
|
"lib/**/*",
|
|
"renderer/**/*",
|
|
"assets/app_icon.ico",
|
|
"assets/app_icon.png"
|
|
],
|
|
"win": {
|
|
"target": [
|
|
"nsis",
|
|
"portable"
|
|
],
|
|
"icon": "assets/app_icon.ico",
|
|
"signAndEditExecutable": false
|
|
},
|
|
"nsis": {
|
|
"oneClick": false,
|
|
"perMachine": false,
|
|
"allowToChangeInstallationDirectory": true,
|
|
"createDesktopShortcut": true
|
|
},
|
|
"afterPack": "scripts/afterPack.cjs"
|
|
}
|
|
}
|