Skip to content

fix(worker-shell): bundle sqlite worker runtime - #144

Open
agent-think[bot] wants to merge 4 commits into
mainfrom
fix/issue-106-sqlite-worker
Open

agent-think[bot] wants to merge 4 commits into
mainfrom
fix/issue-106-sqlite-worker

Conversation

@agent-think

@agent-think agent-think Bot commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #106.

Summary

  • bundle just-bash's SQLite query worker implementation into the optional SQLite module graph
  • provide sql-wasm.wasm as a Dynamic Worker Loader WebAssembly module and adapt sql.js to instantiate it
  • use an in-isolate implementation of just-bash's worker message protocol because workerd does not implement node:worker_threads.Worker
  • add a workerd regression test that creates, persists, and queries a SQLite database through WorkerShellBackend
  • verify the SQLite worker/Wasm content remains exclusive to @cloudflare/computer/shell/sqlite

Verification

  • npm run test:worker-backend --workspace @cloudflare/computer
  • npm exec vitest run --workspace packages/computer -- src/backends/worker-shell/shell-modules.test.ts src/backends/worker-shell/script/partition.test.ts
  • npm run typecheck --workspace @cloudflare/computer
  • npm run build --workspace @cloudflare/computer
  • npm pack --ignore-scripts --workspace @cloudflare/computer (published artifact contains the SQLite query worker and Wasm module)

The generated core group is byte-for-byte unchanged with and without this fix: 1,882,415 generated-file bytes, 1,793,181 module-source bytes, 179 modules, and a 623,950-byte shell.js. Projects that do not import the SQLite subpath therefore do not take a bundle-size increase.


Devin Review

@changeset-bot

changeset-bot Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: dff14a8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@cloudflare/computer Patch
@cloudflare/dofs Patch
@cloudflare/computer-rpc Patch
@cloudflare/computerd Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration devin-ai-integration Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Newer findings are available below. Devin Review posted a newer report on this PR, in addition to the findings presented here.

Devin Review found 3 potential issues.

2 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment on lines +41 to +43
async terminate() {
this.#terminated = true;
return 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 SQLite timeouts cannot stop queries

A CPU-bound query prevents terminate() from running until executeQuery finishes. SQLite limits and shell cancellation cannot stop it, blocking every command in the Dynamic Worker.

Learn more

The original SQLite implementation runs executeQuery in a Node worker thread. Its controller enforces maxSqliteTimeoutMs by terminating that thread. The inline adapter runs the same synchronous sql.js WebAssembly work on the Dynamic Worker's event loop. A timer, abort RPC, or terminate() call cannot execute while that work occupies the isolate. The configured query timeout therefore only takes effect after the query has already returned.

Example: A recursive query that runs for minutes starts with a five-second SQLite timeout. The five-second timer cannot run while WebAssembly executes. The shell isolate remains unavailable until the query naturally finishes instead of returning after five seconds.

Recommended fix: Execute SQLite in a separately terminable Worker-compatible isolate, or add an interruption mechanism inside SQLite that the runtime can trigger independently of the blocked event loop. Do not report successful termination unless the computation has actually stopped.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@pkg-pr-new

pkg-pr-new Bot commented Sep 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@cloudflare/computer@144

commit: cf4baac

just-bash keys its sqlite3 database locks on `fsIdentity ?? fs`, then on
the canonical database path. ShellWorker.exec builds a fresh Bash and
WorkspaceFsAdapter for every execution, and adaptSqliteCommand wraps that
in a fresh Proxy, so each execution landed in its own lock bucket and two
concurrent writers to the same database never contended.

Because writeback replaces the whole database image, the later writer
silently discarded the earlier one's rows rather than failing.

Pin one module-level identity shared by every sqlite3 command in the
isolate and let the canonical path keep distinguishing databases, so
separate databases still run concurrently.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

Devin Review

Comment on lines +62 to +71
source = replaceExactlyOnce(
source,
"export{$e as a,_e as b,Fe as c};",
"const __sqliteCommand=__adaptSqliteCommand(_e);export{$e as a,__sqliteCommand as b,Fe as c};",
"sqlite command export",
);
source =
`import { adaptSqliteCommand as __adaptSqliteCommand } from ${JSON.stringify(
resolve(here, "sqlite-command-adapter.mjs"),
)};\n` + source;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 SQLite adaptation tracks minified output

The plugin rewrites exact minified just-bash symbols while accepting caret upgrades. Routine dependency updates can break package preparation despite unchanged SQLite behavior.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +86 to +93
// WorkerDefenseInDepth belongs around a dedicated thread. Running it
// in the shell's isolate would harden the shell itself after a query.
source = replaceExactlyOnce(
source,
" activateDefense();\n",
"",
"worker defense activation",
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 SQLite loses worker defense layer

Removing activateDefense() leaves the Dynamic Worker as SQLite's only isolation boundary. Review whether that boundary matches the upstream worker threat model.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

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.

worker-shell: sqlite3 is unusable in the published package — sqlite3-worker.js is referenced but its module content is not in the tarball

1 participant