perf(web): run all solves in the worker pool, async live-calc, result… - #77
Conversation
|
Short version: this is the strongest PR of the three and the responsiveness win is real and measurable. It still cannot merge, because a constrained PRO 3D model can now fail to solve at all. Audited commit The win, measured Largest gap between Rendered results were identical across all three. The memo also absorbs repeated work — ten rapid Solve dispatches produced zero engine invocations on #77 against ten on #76. The stale-response discipline in The blocker #76 left a defect where the 3D wire carries a live Svelte To reproduce: PRO mode, load RC QA Diagnostic (PRO), delete its combinations so the single-solve branch is taken, then Solve. The reason nothing catches it is What I would change
Scope note The title says all solves move to the worker pool, but several routes are still synchronous: the 2D manual solve in Not covered I could not drive rapid editing under live calculation from automation, so out-of-order live-calc results are unverified beyond the unit test. Worker crash, malformed reply, and teardown with pending jobs have no injection hook either. One full-suite run out of five reported a single failure that did not reproduce across four subsequent clean runs; it coincided with heavy concurrent load from my own browser testing and I could not identify the test, so I would treat it as unattributed rather than blame this PR. Once the transport is fixed and the fallback covers it, the measured responsiveness gain makes this well worth landing. |
… memo
Single solves and live-calc ran synchronously on the main thread — a large
model froze the UI for the whole solve. The worker pool only served 3D
combos. Now:
- solver-worker handles solve/solve3d messages (objects structured-cloned
both ways, NaN guard in-worker); pool routes jobs least-busy and exposes
solve2D/3DInWorker. PoolUnavailableError falls back to the old sync call,
so Node/vitest and no-Worker browsers behave exactly as before. Failed
initPool no longer poisons the pool; tests can inject fake workers.
- solver-service: validateAndSolve* split into shared prepare (main thread)
+ finalize; new async variants run the engine call in the pool with
identical result shapes and string-error semantics.
- live-calc fully async with stale-response discipline (request counter +
modelVersion gates on every store write; manual solve supersedes
in-flight live calc).
- LRU(6) memo keyed by wire input ('2d:'/'3d:' + JSON.stringify) covering
undo/redo and no-op edits; errors never cached; test hooks exported.
Tests: new solver-pool-async.test.ts (10 — pool/main parity, error parity,
memo hit/miss, stale discard, no-Worker fallback); one spy retargeted to the
async entry. Full suite 2685 passed / 7 skipped; build + tsc clean.
6f23d66 to
3084043
Compare
… memo
Single solves and live-calc ran synchronously on the main thread — a large model froze the UI for the whole solve. The worker pool only served 3D combos. Now:
Tests: new solver-pool-async.test.ts (10 — pool/main parity, error parity, memo hit/miss, stale discard, no-Worker fallback); one spy retargeted to the async entry. Full suite 2685 passed / 7 skipped; build + tsc clean.