hub-runner 0.2.2 → 0.2.3

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.
Files changed (2) hide show
  1. package/main.mjs +41 -8
  2. package/package.json +1 -1
package/main.mjs CHANGED
@@ -2174,17 +2174,17 @@ function createSupervisor({
2174
2174
  warn(`[registry] ! ${entry.name} crashed: ${entry.error}`);
2175
2175
  return changed(entry);
2176
2176
  }
2177
- const delay2 = Math.min(BACKOFF_BASE_MS * 2 ** (entry.crashes.length - 1), BACKOFF_MAX_MS);
2177
+ const delay3 = Math.min(BACKOFF_BASE_MS * 2 ** (entry.crashes.length - 1), BACKOFF_MAX_MS);
2178
2178
  entry.status = "down";
2179
- entry.nextRestartAt = new Date(now + delay2).toISOString();
2180
- warn(`[registry] ${entry.name} exited unexpectedly (${how}); restarting in ${delay2 / 1e3}s`);
2179
+ entry.nextRestartAt = new Date(now + delay3).toISOString();
2180
+ warn(`[registry] ${entry.name} exited unexpectedly (${how}); restarting in ${delay3 / 1e3}s`);
2181
2181
  entry.timer = setTimeout(async () => {
2182
2182
  await untilTreeGone(pgid, tree, KILL_GRACE_MS);
2183
2183
  if (entry.status !== "down" || entry.stopping) return;
2184
2184
  entry.restarts++;
2185
2185
  changed(entry);
2186
2186
  void spawnAgent(entry, { recovered: true });
2187
- }, delay2);
2187
+ }, delay3);
2188
2188
  entry.timer.unref();
2189
2189
  changed(entry);
2190
2190
  }
@@ -2575,7 +2575,7 @@ async function sendToBot(fetchFn, eve, d, context, loadImage) {
2575
2575
  }
2576
2576
 
2577
2577
  // ../../hosted-hub/runner/hub-runner.ts
2578
- import { setTimeout as delay } from "node:timers/promises";
2578
+ import { setTimeout as delay2 } from "node:timers/promises";
2579
2579
 
2580
2580
  // ../../hosted-hub/runner/status.ts
2581
2581
  import { renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
@@ -4547,6 +4547,38 @@ function modelCredential(o) {
4547
4547
  } };
4548
4548
  }
4549
4549
 
4550
+ // ../../hosted-hub/runner/held.ts
4551
+ import { setTimeout as delay } from "node:timers/promises";
4552
+ function heldReports(send, failed) {
4553
+ const told = /* @__PURE__ */ new Map();
4554
+ const now = (bot) => told.has(bot) ? told.get(bot) : null;
4555
+ let sending = Promise.resolve();
4556
+ const tell = (bot, reason) => sending = sending.catch(() => {
4557
+ }).then(async () => {
4558
+ if (now(bot) === reason) return;
4559
+ told.set(bot, void 0);
4560
+ await send({ bot, reason });
4561
+ if (reason) told.set(bot, reason);
4562
+ else told.delete(bot);
4563
+ });
4564
+ return (waiting, why) => {
4565
+ for (const bot of /* @__PURE__ */ new Set([...waiting, ...told.keys()])) {
4566
+ const reason = why(bot);
4567
+ if (now(bot) !== reason) tell(bot, reason).catch(failed);
4568
+ }
4569
+ };
4570
+ }
4571
+ async function stopWithin(stop, ms, signal) {
4572
+ const stopped = new AbortController();
4573
+ await Promise.race([
4574
+ stop.finally(() => stopped.abort()),
4575
+ delay(ms, void 0, { signal: AbortSignal.any([signal, stopped.signal]) }).then(() => {
4576
+ throw new Error(`it did not stop in ${ms / 1e3}s`);
4577
+ }, () => {
4578
+ })
4579
+ ]);
4580
+ }
4581
+
4550
4582
  // ../../hosted-hub/runner/hub-runner.ts
4551
4583
  var realBots = { stage: stageLocal, supervise: createSupervisor };
4552
4584
  var HeldElsewhere = class extends Error {
@@ -4824,7 +4856,7 @@ async function run3(config, bots = realBots) {
4824
4856
  if (restarted.get(name)?.requestedAt !== requestedAt) {
4825
4857
  if (agent) {
4826
4858
  try {
4827
- await supervisor.stop(agent);
4859
+ await stopWithin(supervisor.stop(agent), config.stopTimeoutMs ?? 6e4, shutdown.signal);
4828
4860
  shutdown.signal.throwIfAborted();
4829
4861
  supervisor.start(agent);
4830
4862
  if (!await supervisor.waitUp(agent, 12e4)) throw new Error("it did not come back up");
@@ -4869,7 +4901,7 @@ async function run3(config, bots = realBots) {
4869
4901
  }
4870
4902
  }
4871
4903
  let syncing = null, again = false, drained = null;
4872
- const unsettled = /* @__PURE__ */ new Set();
4904
+ const unsettled = /* @__PURE__ */ new Set(), held = heldReports((body) => hubJson("/api/local-runner/setup", { method: "POST", body: JSON.stringify(body), signal: AbortSignal.timeout(ACK_MS) }), (e) => failed("held report", e));
4873
4905
  async function sync() {
4874
4906
  const work = await hubJson("/api/local-runner/work");
4875
4907
  if (drained && !work.sessions.length && !work.children.length && !work.deliveries.some(([d]) => unsettled.has(d.id))) {
@@ -4897,6 +4929,7 @@ async function run3(config, bots = realBots) {
4897
4929
  for (const [id, abort] of following) if (![...sessions, ...work.children].some((s) => s.sessionId === id)) abort.abort();
4898
4930
  restart(work);
4899
4931
  compact2(work);
4932
+ held(work.deliveries.map(([d]) => d.bot), (bot) => drained ? "draining" : restarting.has(bot) ? "restarting" : !running.has(bot) ? "stopped" : null);
4900
4933
  await Promise.all([
4901
4934
  ...sessions.filter((s) => s.cancel.length).map((s) => cancel(s, work.human).catch((e) => failed("cancel", e))),
4902
4935
  ...work.deliveries.filter(([d]) => (!drained || unsettled.has(d.id)) && running.has(d.bot) && !restarting.has(d.bot) && !dead.has(d.bot) && !retired.has(d.sessionId)).map((q) => deliver(q, work).catch((e) => failed("delivery", e)))
@@ -4953,7 +4986,7 @@ async function run3(config, bots = realBots) {
4953
4986
  } finally {
4954
4987
  clearTimeout(watchdog);
4955
4988
  }
4956
- await delay(RETRY_MS, void 0, { signal: shutdown.signal }).catch(() => {
4989
+ await delay2(RETRY_MS, void 0, { signal: shutdown.signal }).catch(() => {
4957
4990
  });
4958
4991
  }
4959
4992
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hub-runner",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Runs a hub workspace's Mac bots on this Mac under launchd, with no app needed.",
6
6
  "type": "module",