Offload functions to worker threads with shared memory primitives for Node.js.
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(serve): leastConns rotates offset on ties instead of always picking first

Without the rotating offset, sequential requests that arrive after the
previous one completed (counter back to 0) always land on worker 0.
Now ties are broken by a rotating offset — same approach as the core
roundRobin Balancer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+25 -12
+9 -5
src/serve/strategies.ts
··· 1 1 import type { ServerThreadBalancer } from './types.ts'; 2 2 3 - /** Pick the thread with the fewest active connections; ties go to the first. */ 3 + /** Pick the thread with the fewest active connections; ties rotate. */ 4 4 export function leastConns(): ServerThreadBalancer { 5 + let offset = 0; 5 6 return { 6 7 select(threads) { 7 - let best = threads[0]; 8 - for (let i = 1; i < threads.length; i++) { 9 - if (threads[i].conns < best.conns) { 10 - best = threads[i]; 8 + const n = threads.length; 9 + let best = threads[offset % n]; 10 + for (let k = 1; k < n; k++) { 11 + const candidate = threads[(offset + k) % n]; 12 + if (candidate.conns < best.conns) { 13 + best = candidate; 11 14 } 12 15 } 16 + offset++; 13 17 return best; 14 18 }, 15 19 };
+16 -7
test/serve/strategies.test.ts
··· 12 12 const b = leastConns(); 13 13 const t = threads(5, 2, 7); 14 14 assert.strictEqual(b.select(t), t[1]); 15 - const t2 = threads(0, 0, 0); 16 - assert.strictEqual(b.select(t2), t2[0]); // ties → first 17 - const t3 = threads(3, 3, 1); 18 - assert.strictEqual(b.select(t3), t3[2]); 15 + const t2 = threads(3, 3, 1); 16 + assert.strictEqual(b.select(t2), t2[2]); 19 17 }); 20 18 21 - it('is stateless across calls', () => { 19 + it('rotates among tied threads', () => { 22 20 const b = leastConns(); 23 - const t = threads(1, 0, 0); 21 + const t = threads(0, 0, 0, 0); 22 + assert.strictEqual(b.select(t), t[0]); 24 23 assert.strictEqual(b.select(t), t[1]); 25 - assert.strictEqual(b.select(t), t[1]); // same input → same result 24 + assert.strictEqual(b.select(t), t[2]); 25 + assert.strictEqual(b.select(t), t[3]); 26 + assert.strictEqual(b.select(t), t[0]); 27 + }); 28 + 29 + it('picks lowest even when offset rotates', () => { 30 + const b = leastConns(); 31 + const t = threads(0, 0, 0); 32 + b.select(t); // offset now 1 33 + const t2 = threads(5, 0, 5); 34 + assert.strictEqual(b.select(t2), t2[1]); // still picks lowest 26 35 }); 27 36 }); 28 37