Ctrl K
ComunidadGuías…

electron/cua-restart.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Computer control's helper can die while the app runs. It is started again by itself a bounded number of times, and
// what is true meanwhile is what readiness says.
export const HELPER_RESTARTING = "Computer control stopped because its helper crashed. OpenMausBot is restarting it.";
export const HELPER_KEEPS_CRASHING =
  "Computer control's helper keeps crashing, so OpenMausBot stopped restarting it. Quit and reopen OpenMausBot to try again.";

export const RESTART_WAITS_MS = [1_000, 5_000, 15_000];
/** A helper that ran this long was fine: the next crash starts a new count. */
export const STABLE_AFTER_MS = 120_000;

/**
 * `restart()` resolves true when a working helper is back, false when it is not, and "needs-person" when only the person
 * can fix why (the reason already published stays). `report(reason)` publishes why computer control is down.
 * `started()` after any start that gave a working helper; `exited(detail)` when a working one died; `reset()` when the
 * person restarts it or the app stops it, which cancels a waiting restart and forgets the count.
 */
export function createHelperRestarts({
  restart,
  report,
  log = () => {},
  now = Date.now,
  waitsMs = RESTART_WAITS_MS,
  stableAfterMs = STABLE_AFTER_MS,
  setTimer = setTimeout,
  clearTimer = clearTimeout,
}) {
  let failures = 0;
  let startedAt = null;
  let timer = null;
  let epoch = 0;

  const tryAgain = () => {
    if (failures >= waitsMs.length) {
      log(`helper kept crashing; stopped after ${failures} restarts`);
      report(HELPER_KEEPS_CRASHING);
      return;
    }
    const wait = waitsMs[failures++];
    const run = ++epoch;
    report(HELPER_RESTARTING);
    timer = setTimer(async () => {
      timer = null;
      let back = false;
      try {
        back = await restart();
      } catch (error) {
        log(`helper restart failed: ${error?.message ?? error}`);
      }
      if (run !== epoch || back === "needs-person") return;
      if (back) startedAt = now();
      else tryAgain();
    }, wait);
    timer.unref?.();
  };

  return {
    started() {
      startedAt = now();
    },
    exited(detail) {
      if (startedAt !== null && now() - startedAt >= stableAfterMs) failures = 0;
      startedAt = null;
      log(`helper exited: ${detail}`);
      tryAgain();
    },
    reset() {
      epoch++;
      if (timer !== null) clearTimer(timer);
      timer = null;
      failures = 0;
      startedAt = null;
    },
  };
}

/** The Linux runtime publishes its own connection records; a died daemon and a ready one are what restarts need from them. */
export function followLinuxConnection(restarts, connection) {
  if (connection?.status === "ready") restarts.started();
  else if (connection?.reasonCode === "daemon-exited") restarts.exited(`exit ${connection.exitCode ?? connection.exitSignal ?? "unknown"}`);
}