mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-29 22:23:01 +00:00
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
This commit is contained in:
co-authored by
Steven Enamakel
parent
a40272ef45
commit
9376ffc19f
@@ -12,6 +12,27 @@ interface CoreRpcRelayRequest {
|
||||
method: string;
|
||||
params?: unknown;
|
||||
serviceManaged?: boolean;
|
||||
/**
|
||||
* Per-call timeout override in milliseconds. When omitted, defaults to the
|
||||
* global `CORE_RPC_TIMEOUT_MS` (30s). Use for slow-but-alive RPCs such as
|
||||
* first-launch `openhuman.app_state_snapshot` (#2156). Clamped to the same
|
||||
* [MIN, MAX] window as the global default.
|
||||
*/
|
||||
timeoutMs?: number;
|
||||
}
|
||||
|
||||
/** Mirror of `parseCoreRpcTimeoutMs` bounds in `utils/config.ts`. */
|
||||
const PER_CALL_TIMEOUT_MIN_MS = 1_000;
|
||||
const PER_CALL_TIMEOUT_MAX_MS = 10 * 60 * 1_000;
|
||||
|
||||
function resolvePerCallTimeoutMs(override: number | undefined): number {
|
||||
if (override === undefined) return CORE_RPC_TIMEOUT_MS;
|
||||
if (!Number.isFinite(override)) return CORE_RPC_TIMEOUT_MS;
|
||||
const clamped = Math.min(
|
||||
Math.max(Math.round(override), PER_CALL_TIMEOUT_MIN_MS),
|
||||
PER_CALL_TIMEOUT_MAX_MS
|
||||
);
|
||||
return clamped;
|
||||
}
|
||||
|
||||
interface JsonRpcRequestBody {
|
||||
@@ -344,7 +365,8 @@ export async function getCoreRpcToken(): Promise<string | null> {
|
||||
*/
|
||||
export async function testCoreRpcConnection(
|
||||
url: string,
|
||||
tokenOverride?: string
|
||||
tokenOverride?: string,
|
||||
init?: { signal?: AbortSignal }
|
||||
): Promise<Response> {
|
||||
const token = tokenOverride?.trim() || (await getCoreRpcToken());
|
||||
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
||||
@@ -355,6 +377,7 @@ export async function testCoreRpcConnection(
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'core.ping', params: {} }),
|
||||
signal: init?.signal,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -393,6 +416,7 @@ export async function callCoreRpc<T>({
|
||||
method,
|
||||
params,
|
||||
serviceManaged = false, // kept for compatibility; direct frontend RPC does not use relay-level routing.
|
||||
timeoutMs,
|
||||
}: CoreRpcRelayRequest): Promise<T> {
|
||||
void serviceManaged;
|
||||
|
||||
@@ -401,6 +425,7 @@ export async function callCoreRpc<T>({
|
||||
}
|
||||
|
||||
const normalizedMethod = normalizeRpcMethod(method);
|
||||
const effectiveTimeoutMs = resolvePerCallTimeoutMs(timeoutMs);
|
||||
const payload: JsonRpcRequestBody = {
|
||||
jsonrpc: '2.0',
|
||||
id: nextJsonRpcId++,
|
||||
@@ -419,12 +444,14 @@ export async function callCoreRpc<T>({
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
// Bound the fetch to CORE_RPC_TIMEOUT_MS. Without this a hung core
|
||||
// sidecar will block every caller (and the UI) forever. We use a
|
||||
// manual AbortController + setTimeout rather than AbortSignal.timeout()
|
||||
// so test fake timers can drive the abort deterministically.
|
||||
// Bound the fetch. Without this a hung core sidecar would block every
|
||||
// caller (and the UI) forever. We use a manual AbortController +
|
||||
// setTimeout rather than AbortSignal.timeout() so test fake timers can
|
||||
// drive the abort deterministically. Per-call `timeoutMs` (clamped) lets
|
||||
// legitimately-slow RPCs such as first-launch `app_state_snapshot`
|
||||
// (#2156) opt into a longer-but-still-bounded budget.
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), CORE_RPC_TIMEOUT_MS);
|
||||
const timeoutId = setTimeout(() => controller.abort(), effectiveTimeoutMs);
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(rpcUrl, {
|
||||
@@ -437,9 +464,11 @@ export async function callCoreRpc<T>({
|
||||
if (controller.signal.aborted) {
|
||||
// Throw a fully-classified `CoreRpcError` here so the outer catch
|
||||
// doesn't re-wrap a bare `Error` and so callers can branch on
|
||||
// `err.kind === 'timeout'` (Sentry filter, soft toast skip).
|
||||
// `err.kind === 'timeout'` (Sentry filter, soft toast skip). Use
|
||||
// the per-call `effectiveTimeoutMs` so the message reflects the
|
||||
// actual budget (#2156 raised the snapshot path to 90s).
|
||||
throw new CoreRpcError(
|
||||
`Core RPC ${payload.method} timed out after ${CORE_RPC_TIMEOUT_MS}ms`,
|
||||
`Core RPC ${payload.method} timed out after ${effectiveTimeoutMs}ms`,
|
||||
'timeout'
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user