You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
🐛 Bug Report: Dart and Node functions use only one CPU core, regardless of the function's CPU spec #14426
Create a Dart 3.13 and a Node 24 function with spec s-8vcpu-8gb (or any spec with more than one CPU) on a host with 4 cores.
In the function, do a fixed amount of CPU work per execution (≈ 20 ms on one core; we used a xorshift loop of 14 million rounds).
Execute it synchronously with 20 and 80 concurrent connections and compare with the same work moved to other cores inside the function (Dart Isolate.run, Node worker_threads pool).
👍 Expected behavior
A function with a spec of N CPUs can use up to N cores for concurrent executions, as the Python runtime does (gunicorn starts one worker per spec CPU) and Go does (goroutines on all cores).
👎 Actual Behavior
The Dart and Node runtime servers handle all executions of a runtime container on a single thread:
Dart: shelf_io.serve(...) in the main isolate, no shared: true and no additional isolates (server.dart L197).
So as soon as a function does real CPU work, executions queue behind each other on one core, although the container may use 8 CPUs. Executions per second, 2 rounds each (Appwrite 2.4.0, 4-core executor node):
Variant
20 connections
p50
80 connections
p50
Dart, work in the handler (current)
52 / 50
385–391 ms
55 / 55
1,552–1,555 ms
Dart, Isolate.run per execution
138 / 137
146–147 ms
–
–
Dart, fixed isolate pool
136 / 134
131–140 ms
137 / 136
623–655 ms
Node, work in the handler (current)
50 / 51
395–400 ms
54 / 55
1,552–1,571 ms
Node, new worker_thread per execution
36 / 38
524–547 ms
–
–
Node, fixed worker pool
132 / 134
125–136 ms
136 / 137
472–560 ms
Spreading the work gives ×2.6–2.7 throughput and −60 % p50. After that, the 4 cores of the node are the limit (93–95 % CPU, shared with the API and the executor).
One core caps a function at 1000 / ms of CPU per execution executions per second (≈ 50/s at 20 ms), no matter which spec the user picked.
Start-up cost per execution without any work (median of 15, 2 rounds): Dart Isolate.run ≈ +1.6 ms, Node worker pool ≈ +0.5 ms, new Node worker_thread per execution ≈ +30 ms.
Users can work around it inside their function (as above), but that is not obvious. The spec suggests more CPUs help, and for Dart and Node they don't.
🎲 Appwrite version
2.4.0 (executor 0.29.0, openruntimes/dart:v5-3.13, openruntimes/node:v5-24). Same server code on open-runtimes main (da714e7).
💻 Operating system
Linux (Debian 12), Docker
🧱 Your Environment
Self-hosted. Executor and runtimes on a 4 vCPU node together with an API container, a second API node, Postgres, Redis and ClickHouse on a separate node. _APP_COMPUTE_CPUS=0, so runtimes get the s-8vcpu-8gb spec.
💡 Suggested fix
Let the runtime servers scale with OPEN_RUNTIMES_CPUS, like the Python runtime already does: Dart could start one isolate per CPU, each calling shelf_io.serve(..., shared: true) on port 3000; Node could use node:cluster (or SO_REUSEPORT) with one worker per CPU. User code then runs in several isolates or processes, so global state is per worker. That needs to be documented, as it already is implicitly for Python.
At least, document that Dart, Node (and probably Bun) execute on one core per runtime, and show Isolate.run and a worker_threads pool as the way to use the spec's CPUs.
👀 Have you spent some time to check if this issue has been raised before?
Hi @playb0t, I'd be interested in contributing to this issue. I confirmed that the Cloud Console config and Claude Desktop documentation still describe the mcp-remote setup as the primary path.
I noticed you mentioned having a local patch ready. Are you planning to submit that work, or is the issue available for someone else to implement? I'd be happy to help with the UI, documentation, localization, and regression tests if the work isn't already underway.
Activity
GarvSaxena commentedon Oct 16, 2026
Hi @playb0t, I'd be interested in contributing to this issue. I confirmed that the Cloud Console config and Claude Desktop documentation still describe the
mcp-remotesetup as the primary path.I noticed you mentioned having a local patch ready. Are you planning to submit that work, or is the issue available for someone else to implement? I'd be happy to help with the UI, documentation, localization, and regression tests if the work isn't already underway.