@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
364 lines (363 loc) • 14.7 kB
JavaScript
import { spawn } from "node:child_process";
import { handleProxyTokenBudgetMessage, releaseProxyTokenBudgetOwner, } from "./proxyTokenBudget.js";
import { ErrorFactory } from "../utils/errorHandling.js";
import { isProxyWorkerStatusMessage, PROXY_SOCKET_WORKER_ENV, PROXY_SOCKET_OFFER_TIMEOUT, PROXY_SOCKET_COMMIT_TIMEOUT, } from "./rollingWorkerProtocol.js";
/**
* Spawn a generation-specific IPC worker with separate offer and commit
* ownership deadlines.
*/
export function spawnProxySocketWorker(options) {
const socketAckTimeoutMs = Math.max(1, options.socketAckTimeoutMs ?? 30_000);
let nextSocketId = 0;
let controlBeforeHandle = false;
let workerCommitAcknowledgement = false;
const pendingSockets = new Map();
const statusListeners = new Set();
const pendingStatusMessages = [];
let spawnError;
let budgetResponseFailure;
let budgetTerminationTimeout;
const child = (options.spawn ?? spawn)(options.command, options.args, {
env: {
...process.env,
...options.env,
[PROXY_SOCKET_WORKER_ENV]: "1",
NEUROLINK_PROXY_WORKER_GENERATION: String(options.generation),
NEUROLINK_PROXY_WORKER_EXPECTED_VERSION: options.expectedVersion,
},
stdio: [
"ignore",
options.stdout ?? "inherit",
options.stderr ?? "inherit",
"ipc",
],
});
const childPid = child.pid;
const publishStatus = (message) => {
if (statusListeners.size === 0) {
if (pendingStatusMessages.length >= 32) {
pendingStatusMessages.shift();
}
pendingStatusMessages.push(message);
return;
}
for (const listener of statusListeners) {
listener(message);
}
};
child.once("error", (error) => {
spawnError = error;
if (!childPid) {
return;
}
publishStatus({
type: "proxy-worker:fatal",
generation: options.generation,
pid: childPid,
message: error.message,
});
});
if (!childPid) {
child.kill("SIGTERM");
throw ErrorFactory.proxyWorkerLifecycle("proxy worker spawn did not return a pid");
}
/**
* Finish a handoff once and cancel its worker-side copy on uncertain
* delivery.
*/
const settleSocket = (socketId, error) => {
const pending = pendingSockets.get(socketId);
if (!pending) {
return;
}
pendingSockets.delete(socketId);
clearTimeout(pending.timeout);
if (error && child.connected) {
try {
child.send({
type: "proxy-worker:socket-cancel",
generation: options.generation,
socketId,
}, () => undefined);
}
catch {
// The supervisor will quarantine the worker after the failed transfer.
}
}
if (!error) {
pending.socket.destroy();
}
pending.callback(error);
};
/** Lost budget replies leave unknown leases; release them only after exit. */
const quarantineBudgetDeliveryFailure = () => {
if (budgetResponseFailure) {
return;
}
const error = ErrorFactory.proxyWorkerLifecycle(`proxy worker ${childPid} token budget response delivery failed`);
budgetResponseFailure = error;
// An IPC-disconnected worker may ignore graceful shutdown. Retain its
// reservation occupancy until exit, but bound how long it can survive.
budgetTerminationTimeout = setTimeout(() => {
if (child.exitCode === null && child.signalCode === null) {
child.kill("SIGKILL");
}
}, 1_000);
budgetTerminationTimeout.unref?.();
try {
publishStatus({
type: "proxy-worker:fatal",
generation: options.generation,
pid: childPid,
message: error.message,
});
for (const socketId of [...pendingSockets.keys()]) {
settleSocket(socketId, error);
}
}
finally {
if (child.exitCode === null && child.signalCode === null) {
child.kill("SIGTERM");
}
}
};
/**
* Accept messages only from this worker and start a fresh deadline for
* the commit phase.
*/
const onInternalMessage = (message) => {
if (isProxyWorkerStatusMessage(message) &&
message.type === "proxy-worker:ready" &&
message.generation === options.generation &&
message.pid === childPid) {
controlBeforeHandle =
message.socketOfferProtocol === "control-before-handle";
workerCommitAcknowledgement =
message.socketCommitProtocol === "worker-ack";
}
if (isProxyWorkerStatusMessage(message) &&
message.type === "proxy-worker:socket-committed" &&
message.generation === options.generation &&
message.pid === childPid) {
const pending = pendingSockets.get(message.socketId);
if (!pending || !pending.accepted || !pending.descriptorSent) {
return;
}
settleSocket(message.socketId);
return;
}
if (isProxyWorkerStatusMessage(message) &&
message.type === "proxy-worker:socket-accepted" &&
message.generation === options.generation &&
message.pid === childPid) {
const pending = pendingSockets.get(message.socketId);
if (!pending || pending.accepted) {
return;
}
if (Date.now() >= pending.deadlineAt) {
const error = Object.assign(new Error("Socket admission deadline expired before commit"), {
code: PROXY_SOCKET_OFFER_TIMEOUT,
socketNeverTransferred: !pending.descriptorSent,
});
settleSocket(message.socketId, error);
return;
}
const commitBudgetMs = Math.min(socketAckTimeoutMs, pending.deadlineAt - Date.now());
const minimumCommitWindowMs = Math.min(socketAckTimeoutMs, 1_000);
if (commitBudgetMs < minimumCommitWindowMs) {
settleSocket(message.socketId, Object.assign(new Error("Socket admission deadline too close for commit"), {
code: PROXY_SOCKET_OFFER_TIMEOUT,
socketNeverTransferred: !pending.descriptorSent,
}));
return;
}
pending.accepted = true;
// Acceptance and commit are distinct phases. A late acceptance must not
// inherit an almost-expired offer timer and kill established streams.
clearTimeout(pending.timeout);
pending.timeout = setTimeout(() => {
const error = new Error(`proxy worker ${childPid} socket commit remained pending for ${commitBudgetMs}ms`);
error.code = PROXY_SOCKET_COMMIT_TIMEOUT;
settleSocket(message.socketId, error);
}, commitBudgetMs);
pending.timeout.unref?.();
try {
const commit = {
type: "proxy-worker:socket-commit",
generation: options.generation,
socketId: message.socketId,
};
if (!pending.descriptorSent) {
// Mark ambiguous before calling IPC: even a thrown/send callback error
// cannot prove the descriptor was not delivered and consumed.
pending.descriptorSent = true;
child.send(commit, pending.socket, { keepOpen: true }, (error) => {
if (error || !workerCommitAcknowledgement) {
settleSocket(message.socketId, error ?? undefined);
}
});
}
else {
child.send(commit, (error) => {
if (error || !workerCommitAcknowledgement) {
settleSocket(message.socketId, error ?? undefined);
}
});
}
}
catch (error) {
settleSocket(message.socketId, error instanceof Error ? error : new Error(String(error)));
}
}
};
child.on("message", (message) => {
if (budgetResponseFailure) {
return;
}
if (handleProxyTokenBudgetMessage(message, { pid: childPid, generation: options.generation }, (response) => {
if (!child.connected) {
quarantineBudgetDeliveryFailure();
return;
}
try {
child.send(response, (error) => {
if (error) {
quarantineBudgetDeliveryFailure();
}
});
}
catch {
quarantineBudgetDeliveryFailure();
}
})) {
return;
}
onInternalMessage(message);
if (isProxyWorkerStatusMessage(message)) {
publishStatus(message);
}
});
child.once("exit", (code, signal) => {
clearTimeout(budgetTerminationTimeout);
releaseProxyTokenBudgetOwner(childPid, options.generation);
for (const socketId of [...pendingSockets.keys()]) {
settleSocket(socketId, ErrorFactory.proxyWorkerLifecycle(`proxy worker ${childPid} exited before socket transfer committed (code=${code ?? "none"}, signal=${signal ?? "none"})`, {
workerPid: childPid,
generation: options.generation,
exitCode: code,
signal,
}));
}
});
const sendControl = (message) => {
if (budgetResponseFailure) {
throw budgetResponseFailure;
}
if (!child.connected) {
throw new Error(`proxy worker ${childPid} IPC channel is closed`);
}
child.send(message, (error) => {
if (error && child.exitCode === null && child.signalCode === null) {
child.kill("SIGTERM");
}
});
};
return {
pid: childPid,
socketTransferTimeoutMs: 2 * socketAckTimeoutMs,
sendControl,
sendSocket: (generation, socket, callback, deadlineAt = Date.now() + 2 * socketAckTimeoutMs) => {
if (Date.now() >= deadlineAt) {
const error = Object.assign(new Error("Socket admission deadline expired before offer"), {
code: PROXY_SOCKET_OFFER_TIMEOUT,
socketNeverTransferred: true,
});
callback(error);
return;
}
if (budgetResponseFailure) {
callback(budgetResponseFailure);
return;
}
if (!child.connected) {
callback(new Error(`proxy worker ${childPid} IPC channel is closed`));
return;
}
const socketId = `${generation}:${++nextSocketId}`;
const timeout = setTimeout(() => {
const error = Object.assign(new Error(`proxy worker ${childPid} did not accept socket within ${socketAckTimeoutMs}ms`), {
code: PROXY_SOCKET_OFFER_TIMEOUT,
socketNeverTransferred: pendingSockets.get(socketId)?.descriptorSent === false,
});
settleSocket(socketId, error);
}, Math.max(0, Math.min(socketAckTimeoutMs, deadlineAt - Date.now())));
timeout.unref?.();
pendingSockets.set(socketId, {
socket,
callback,
timeout,
accepted: false,
deadlineAt,
descriptorSent: !controlBeforeHandle,
});
try {
const onSent = (error) => {
if (error) {
settleSocket(socketId, error);
}
};
if (controlBeforeHandle) {
child.send({ type: "proxy-worker:socket-offer", generation, socketId }, onSent);
}
else {
// Old workers require descriptor-first offers. They may buffer input
// before commit, so their timed-out offers are never safe to retry.
child.send({ type: "proxy-worker:socket", generation, socketId }, socket, { keepOpen: true }, onSent);
}
}
catch (error) {
settleSocket(socketId, error instanceof Error ? error : new Error(String(error)));
}
},
terminate: (signal = "SIGTERM") => {
if (child.exitCode === null && child.signalCode === null) {
child.kill(signal);
}
},
onMessage: (listener) => {
statusListeners.add(listener);
if (pendingStatusMessages.length > 0) {
const buffered = pendingStatusMessages.splice(0);
queueMicrotask(() => {
if (statusListeners.has(listener)) {
for (const message of buffered) {
listener(message);
}
}
});
}
else if (spawnError) {
const error = spawnError;
queueMicrotask(() => {
if (statusListeners.has(listener)) {
listener({
type: "proxy-worker:fatal",
generation: options.generation,
pid: childPid,
message: error.message,
});
}
});
}
return () => statusListeners.delete(listener);
},
onExit: (listener) => {
if (child.exitCode !== null || child.signalCode !== null) {
queueMicrotask(() => listener(child.exitCode, child.signalCode));
return () => undefined;
}
child.on("exit", listener);
return () => child.off("exit", listener);
},
};
}