🐛 Bug Report: Dart and Node functions use only one CPU core, regardless of the function's CPU spec · Issue #14426 · appwrite/appwrite · GitHub
Skip to content

🐛 Bug Report: Dart and Node functions use only one CPU core, regardless of the function's CPU spec #14426

Open

Description

@JoshiJoshiJoshi

👟 Reproduction steps

  1. 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.
  2. 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).
  3. 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:

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?

  • I checked and didn't find a similar issue

🏢 Have you read the Code of Conduct?

  • I have read the Code of Conduct

Activity

  1. GarvSaxena commented on Oct 16, 2026

    @GarvSaxena

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    product / databasesFixes and upgrades for the Appwrite Database.product / functionsFixes and upgrades for the Appwrite Functions.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions