Skip to content

perf: stream canvas asset serving#588

Closed
JustYannicc wants to merge 115 commits into
SuperCmdLabs:mainfrom
JustYannicc:codex/perf-wave4-canvas-asset-serving
Closed

perf: stream canvas asset serving#588
JustYannicc wants to merge 115 commits into
SuperCmdLabs:mainfrom
JustYannicc:codex/perf-wave4-canvas-asset-serving

Conversation

@JustYannicc

Copy link
Copy Markdown
Collaborator

What changed

  • Serve sc-asset://canvas-lib/... through net.fetch(file://...) and wrap the file-backed body with explicit canvas-lib content type and immutable cache headers.
  • Added a focused canvas asset protocol helper that rejects bad, empty, and escaping canvas-lib paths before fetching.
  • Added async getSceneAsync and getThumbnailAsync canvas store reads, and wired the canvas IPC handlers to them.
  • Expanded the canvas asset event-loop measurement script with buffered-response, stream-response, buffered HTTP, and stream HTTP serving scenarios.
  • Added focused Node tests for canvas asset status/path/header behavior and async canvas scene/thumbnail reads.

Why

Canvas library asset serving previously read the whole file into the main process before responding. Canvas scene and thumbnail IPC reads also used synchronous file reads. The new paths reduce main-process buffering and avoid synchronous canvas IPC file reads while preserving existing fallbacks.

Compatibility impact

Canvas asset URLs and canvas IPC return shapes are unchanged. Missing canvas-lib files still return 404; empty or malformed canvas-lib paths return 400. Missing/invalid scenes still return an empty scene, and missing thumbnails still return null.

How tested

  • node --test scripts/test-canvas-asset-serving.mjs
  • pnpm test
  • pnpm run build:main
  • npm run build:main (local npm shim reports npm is disabled and runs pnpm)
  • Codex LSP diagnostics on src/main/main.ts, src/main/canvas-store.ts, and src/main/sc-asset-protocol.ts: no diagnostics found

Performance evidence

Expanded harness: node scripts/measure-canvas-asset-event-loop.mjs with 32 MB x8 files, 268435456 bytes served per measurement.

  • Baseline from audit on this stack: sync read elapsed 23.776 ms; async read elapsed 27.477 ms.
  • Current sync baseline: elapsed 26.817 ms, max delay 1.437 ms, p95 delay 1.437 ms.
  • Current async read baseline: elapsed 32.707 ms, max delay 1.467 ms, p95 delay 1.274 ms.
  • Old buffered Response: elapsed 43.934 ms, max delay 3.881 ms, p95 delay 1.900 ms.
  • New file stream Response: elapsed 124.024 ms, max delay 2.224 ms, p95 delay 1.080 ms.
  • Old buffered HTTP serving: elapsed 203.846 ms, max delay 7.590 ms, p95 delay 2.746 ms.
  • New stream HTTP serving: elapsed 328.558 ms, max delay 3.985 ms, p95 delay 1.372 ms.

The stream cases trade total in-process harness elapsed for lower peak and p95 event-loop delay during serving and avoid constructing a full asset buffer in the protocol handler.

Stack validation

Started from codex/perf-wave3-integration-stack-20260704 stack point 206eab8280a2eb91a57e4e74ea6df99e45a55cb4; branch codex/perf-wave4-canvas-asset-serving was created from that detached HEAD.

Replaces

None.

…perf-wave2-integration-stack-20260704

# Conflicts:
#	src/renderer/src/raycast-api/hooks/use-cached-promise.ts
…perf-wave2-integration-stack-20260704

# Conflicts:
#	src/renderer/src/raycast-api/list-runtime-renderers.tsx
#	src/renderer/src/raycast-api/list-runtime.tsx
…perf-wave2-integration-stack-20260704

# Conflicts:
#	src/renderer/src/CameraExtension.tsx
…perf-wave2-integration-stack-20260704

# Conflicts:
#	src/renderer/src/raycast-api/list-runtime.tsx
…perf-wave2-integration-stack-20260704

# Conflicts:
#	scripts/bench-script-command-discovery.mjs
#	scripts/benchmark-file-search-delete-batch.mjs
#	scripts/lib/script-command-runner-harness.mjs
#	scripts/lib/ts-import.mjs
#	scripts/test-file-search-delete-batch.mjs
#	scripts/test-script-command-runner.mjs
#	src/main/file-search-index.ts
#	src/main/main.ts
…perf-wave2-integration-stack-20260704

# Conflicts:
#	scripts/lib/script-command-runner-harness.mjs
#	scripts/lib/ts-import.mjs
#	scripts/test-extension-lifecycle-sandbox.mjs
#	scripts/test-script-command-runner.mjs
#	src/main/main.ts
#	src/renderer/src/ExtensionView.tsx
…perf-wave2-integration-stack-20260704

# Conflicts:
#	.github/workflows/project-checks.yml
#	scripts/test-root-search-perf.mjs
#	src/renderer/src/CameraExtension.tsx
#	src/renderer/src/raycast-api/list-runtime.tsx
…erf-wave3-integration-stack-20260704

# Conflicts:
#	package.json
#	scripts/measure-extension-bundle-cache.mjs
#	scripts/test-icon-runtime-file-icon-cache.mjs
#	src/main/extension-runner.ts
#	src/renderer/src/components/HiddenExtensionRunners.tsx
#	src/renderer/src/raycast-api/icon-runtime-render.tsx
…/perf-wave3-integration-stack-20260704

# Conflicts:
#	scripts/test-browser-search-performance.mjs
#	scripts/test-root-search-perf.mjs
@JustYannicc

Copy link
Copy Markdown
Collaborator Author

Superseded by the clean consolidated wave4 renderer/Raycast PR: #599. That branch contains this PR's covered change on current main without the inherited broad-stack noise.

@JustYannicc JustYannicc closed this Jul 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant