Skip to content

perf(runner): O(N) array lookup in requestToActor causes severe CPU bottleneck under high load #5581

Description

@iinaa-eimrit

The Bug

In engine/sdks/typescript/runner/src/tunnel.ts, the Tunnel class uses an array to map incoming requests to their respective actors:

	#requestToActor: Array<{
		gatewayId: GatewayId;
		requestId: RequestId;
		actorId: string;
	}> = [];

Every single time a message or request chunk is received, the code does an O(N) linear scan over this array using .find() and arraysEqual():

	getRequestActor(
		gatewayId: GatewayId,
		requestId: RequestId,
	): RunnerActor | undefined {
		const entry = this.#requestToActor.find(
			(entry) =>
				arraysEqual(entry.gatewayId, gatewayId) &&
				arraysEqual(entry.requestId, requestId),
		);
// ...

Additionally, cleaning up the request performs an O(N) .findIndex() followed by an O(N) .splice().

The Impact

If there are 10,000 active concurrent requests/WebSockets on a single runner, every incoming event (e.g. HTTP body chunk, WS message) will iterate through 10,000 array elements doing byte-by-byte comparisons. This results in O(N^2) processing overhead and will easily peg the Node.js event loop at 100% CPU under load, severely degrading throughput.

The Fix

We should refactor #requestToActor to use a Map<string, string> (using a composite key like ${idToStr(gatewayId)}:${idToStr(requestId)}), converting all lookups, inserts, and deletes to O(1).


Hey @jog1t, I noticed this bottleneck while studying the TypeScript SDK runner architecture! Could you please assign this issue to me? I'd love to submit a PR to refactor this into an O(1) Map!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions