Last active
July 2, 2026 04:19
-
-
Save maiah/46e65fa88d6f10fa0245e6e64942038f to your computer and use it in GitHub Desktop.
Spawn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Semaphore } from "es-toolkit"; | |
| const totalCpuCores = 8; // TODO: Should be set to total number of cpu cores | |
| const totalClients = Math.ceil(totalCpuCores * 1.5); // We want to have more clients than the number of cpu cores to avoid starvation | |
| const lock = new Semaphore(totalClients); | |
| class RpcClient { | |
| createAccount(name: string): Promise<string> { | |
| return Promise.resolve(`Account ${name} created`); | |
| } | |
| onError(callback: (code: number | Error) => void) { | |
| callback(new Error("Error")); | |
| } | |
| onExit(callback: (code: number) => void) { | |
| callback(0); | |
| } | |
| } | |
| const rpcClients: RpcClient[] = []; | |
| function createClient(id: number) { | |
| const rpcClient = new RpcClient(); | |
| rpcClient.onError(() => { | |
| // TODO: Implement exponential backoff on retrying to create a new client | |
| setTimeout(() => { | |
| const newRpcClient = createClient(id); | |
| rpcClients.splice(id, 1, newRpcClient); | |
| }, 1_000); | |
| }); | |
| rpcClient.onExit((code: number) => { | |
| if (code !== 0) { | |
| // TODO: Implement exponential backoff on retrying to create a new client | |
| setTimeout(() => { | |
| const newRpcClient = createClient(id); | |
| rpcClients.splice(id, 1, newRpcClient); | |
| }, 1_000); | |
| } | |
| }); | |
| return rpcClient; | |
| } | |
| for (let i = 0; i < totalClients; i++) { | |
| rpcClients.push(createClient(i)); | |
| } | |
| let currentClient = 0; | |
| function getNextRpcClient() { | |
| if (currentClient >= rpcClients.length) { | |
| currentClient = 0; | |
| } | |
| // TODO: Implement a check if client is in error state and if so, retry to create a new client | |
| const client = rpcClients[currentClient]; | |
| currentClient++; | |
| return client; | |
| } | |
| async function spawn<T>(fn: (client: RpcClient) => Promise<T>) { | |
| await lock.acquire(); | |
| try { | |
| const client = getNextRpcClient(); | |
| return await fn(client); | |
| } catch (error) { | |
| console.error("Error in spawn:", error); | |
| } finally { | |
| lock.release(); | |
| } | |
| } | |
| async function getRpcClient() { | |
| await lock.acquire(); | |
| return { | |
| client: getNextRpcClient(), | |
| release: () => lock.release(), | |
| }; | |
| } | |
| async function main() { | |
| const account = await spawn(async (client) => { | |
| return await client.createAccount("John Doe"); | |
| }); | |
| console.log("account:", account); | |
| const { client, release } = await getRpcClient(); | |
| try { | |
| await client.createAccount("John Doe"); | |
| } finally { | |
| release(); | |
| } | |
| } | |
| main().catch(console.error); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment