@remcp/remcp 0.2.56 → 0.2.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/agent.mjs +39 -0
package/package.json
CHANGED
package/src/agent.mjs
CHANGED
|
@@ -21,6 +21,10 @@ export { localRuntimeEntry, supervisorRestart, updateDecision } from './agent-up
|
|
|
21
21
|
|
|
22
22
|
const UPDATE_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
23
23
|
const UPDATE_CHECK_TIMEOUT_MS = 5000;
|
|
24
|
+
// A deployment can briefly leave one HA replica advertising the previous release. Recheck a few
|
|
25
|
+
// times after a stable connection instead of making that unlucky first answer stick for six hours.
|
|
26
|
+
const POST_CONNECT_UPDATE_RECHECK_DELAYS_MS = Object.freeze([60_000, 5 * 60_000, 15 * 60_000]);
|
|
27
|
+
const POST_CONNECT_UPDATE_RECHECK_JITTER_MS = 30_000;
|
|
24
28
|
// A version that failed to install is retried after this cooldown instead of on every reconnect.
|
|
25
29
|
const UPDATE_RETRY_COOLDOWN_MS = 30 * 60 * 1000;
|
|
26
30
|
const METRICS_INTERVAL_MS = 60_000;
|
|
@@ -75,12 +79,22 @@ export async function runAgent(options) {
|
|
|
75
79
|
const callTimeoutMs = Math.max(5_000, Number(options.rpcTimeoutMs || 120000) - CALL_TIMEOUT_MARGIN_MS);
|
|
76
80
|
const telemetryEnabled = options.telemetryEnabled !== false;
|
|
77
81
|
const persistState = typeof options.persistState === 'function' ? options.persistState : () => {};
|
|
82
|
+
const postConnectUpdateRecheckDelaysMs = (Array.isArray(options.updateRecheckDelaysMs)
|
|
83
|
+
? options.updateRecheckDelaysMs
|
|
84
|
+
: POST_CONNECT_UPDATE_RECHECK_DELAYS_MS)
|
|
85
|
+
.map(Number)
|
|
86
|
+
.filter(delay => Number.isFinite(delay) && delay >= 0 && delay < UPDATE_CHECK_INTERVAL_MS)
|
|
87
|
+
.slice(0, 3);
|
|
88
|
+
const postConnectUpdateRecheckJitterMs = Number.isFinite(Number(options.updateRecheckJitterMs))
|
|
89
|
+
? Math.max(0, Math.min(60_000, Number(options.updateRecheckJitterMs)))
|
|
90
|
+
: POST_CONNECT_UPDATE_RECHECK_JITTER_MS;
|
|
78
91
|
let stopping = false;
|
|
79
92
|
let revoked = false;
|
|
80
93
|
const inFlight = new Map();
|
|
81
94
|
let activeSocket;
|
|
82
95
|
let reconnects = 0;
|
|
83
96
|
let reconnectTimer = null;
|
|
97
|
+
let postConnectUpdateTimers = [];
|
|
84
98
|
// Set when a replica asks this agent to move before it is replaced; the close handler reads it.
|
|
85
99
|
let askedToReconnect = false;
|
|
86
100
|
let pendingRequests = 0;
|
|
@@ -377,6 +391,7 @@ export async function runAgent(options) {
|
|
|
377
391
|
reportInstallOnce();
|
|
378
392
|
flushTelemetry();
|
|
379
393
|
void checkForUpdate();
|
|
394
|
+
schedulePostConnectUpdateChecks();
|
|
380
395
|
});
|
|
381
396
|
ws.on('message', raw => {
|
|
382
397
|
let message;
|
|
@@ -392,6 +407,7 @@ export async function runAgent(options) {
|
|
|
392
407
|
}
|
|
393
408
|
});
|
|
394
409
|
ws.on('close', code => {
|
|
410
|
+
clearPostConnectUpdateChecks();
|
|
395
411
|
for (const controller of inFlight.values()) controller.abort();
|
|
396
412
|
if (stopping) return;
|
|
397
413
|
// 1013 ('reconnect') is what a replica sends before it is replaced by a deployment. The machine
|
|
@@ -436,6 +452,28 @@ export async function runAgent(options) {
|
|
|
436
452
|
let lastAttemptAt = 0;
|
|
437
453
|
let lastUpdateCheckError = '';
|
|
438
454
|
let lastUpdateCheckErrorAt = 0;
|
|
455
|
+
|
|
456
|
+
function clearPostConnectUpdateChecks() {
|
|
457
|
+
for (const timer of postConnectUpdateTimers) clearTimeout(timer);
|
|
458
|
+
postConnectUpdateTimers = [];
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function schedulePostConnectUpdateChecks() {
|
|
462
|
+
clearPostConnectUpdateChecks();
|
|
463
|
+
if (options.autoUpdate === false) return;
|
|
464
|
+
for (const delay of postConnectUpdateRecheckDelaysMs) {
|
|
465
|
+
const jitter = postConnectUpdateRecheckJitterMs > 0
|
|
466
|
+
? Math.floor(Math.random() * (postConnectUpdateRecheckJitterMs + 1))
|
|
467
|
+
: 0;
|
|
468
|
+
const timer = setTimeout(() => {
|
|
469
|
+
postConnectUpdateTimers = postConnectUpdateTimers.filter(candidate => candidate !== timer);
|
|
470
|
+
void checkForUpdate();
|
|
471
|
+
}, delay + jitter);
|
|
472
|
+
timer.unref?.();
|
|
473
|
+
postConnectUpdateTimers.push(timer);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
439
477
|
async function checkForUpdate() {
|
|
440
478
|
if (options.autoUpdate === false) return;
|
|
441
479
|
if (updateInFlight) return;
|
|
@@ -550,6 +588,7 @@ export async function runAgent(options) {
|
|
|
550
588
|
runtimeToolsRetryTimer = null;
|
|
551
589
|
clearTimeout(reconnectTimer);
|
|
552
590
|
reconnectTimer = null;
|
|
591
|
+
clearPostConnectUpdateChecks();
|
|
553
592
|
if (telemetryTimer) clearInterval(telemetryTimer);
|
|
554
593
|
clearInterval(telemetryFlushTimer);
|
|
555
594
|
clearInterval(updateTimer);
|