MCPcopy Index your code
hub / github.com/ether/etherpad / expressCreateServer

Function expressCreateServer

src/node/updater/index.ts:502–567  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

500
501/** Hook entry point — called by ep.json on createServer. */
502export const expressCreateServer = async (): Promise<void> => {
503 detectedMethod = await detectInstallMethod({
504 override: settings.updates.installMethod,
505 rootDir: settings.root,
506 });
507 logger.info(`updater: install method = ${detectedMethod}, tier = ${settings.updates.tier}`);
508
509 // Tier 2: if the previous boot left the state in pending-verification, arm
510 // the health-check timer (or force rollback when bootCount has climbed past
511 // the crash-loop threshold). This must run BEFORE polling starts so the
512 // rollback can fire even if the version checker is misconfigured.
513 const state = await getCurrentState();
514 pendingVerification = checkPendingVerification(state, getRollbackDeps());
515
516 // Boot-time failure notification. If a previous run produced a failure
517 // outcome whose admin email we haven't already sent (lastFailureKey
518 // dedupe), fire it now. Covers:
519 // - health-check timeout rollback on the previous boot
520 // - crash-loop forced rollback (detected on a later boot)
521 // - preflight-failed where we never got to send (e.g. process kill)
522 // - rollback-failed terminal that the operator hasn't acknowledged
523 // Fire-and-forget — the rest of boot must proceed regardless.
524 const failureOutcome = state.lastResult?.outcome === 'rolled-back' ? 'rolled-back'
525 : state.lastResult?.outcome === 'rollback-failed' ? 'rollback-failed'
526 : state.lastResult?.outcome === 'preflight-failed' ? 'preflight-failed'
527 : null;
528 if (failureOutcome && state.lastResult) {
529 void notifyApplyFailure({
530 outcome: failureOutcome,
531 targetTag: state.lastResult.targetTag,
532 reason: state.lastResult.reason ?? failureOutcome,
533 });
534 }
535
536 // Tier 3: instantiate the scheduler unless updates are entirely disabled.
537 // The runner is purely in-memory — the persisted state file is the source
538 // of truth for "is something scheduled." On `tier: "off"` we explicitly
539 // clear any previously-persisted scheduled state to idle so a stale
540 // schedule from a prior boot can't auto-fire after the operator opted
541 // out (Qodo #1).
542 if (settings.updates.tier === 'off') {
543 if (state.execution.status === 'scheduled') {
544 logger.info(
545 `updater: discarding pending Tier 3 schedule for ${state.execution.targetTag} ` +
546 `because updates.tier="off"`);
547 state.execution = {status: 'idle'};
548 await saveState(stateFilePath(), state);
549 }
550 } else {
551 scheduler = createSchedulerRunner({
552 now: () => new Date(),
553 setTimer: (cb, ms) => setTimeout(cb, ms),
554 clearTimer: clearTimeout,
555 triggerApply: schedulerTriggerApply,
556 });
557 if (state.execution.status === 'scheduled') {
558 logger.info(`updater: rehydrating Tier 3 schedule for ${state.execution.targetTag} at ${state.execution.scheduledFor}`);
559 scheduler.arm({

Callers

nothing calls this directly

Calls 9

detectInstallMethodFunction · 0.90
checkPendingVerificationFunction · 0.90
saveStateFunction · 0.90
createSchedulerRunnerFunction · 0.90
getCurrentStateFunction · 0.85
getRollbackDepsFunction · 0.85
notifyApplyFailureFunction · 0.85
stateFilePathFunction · 0.85
startPollingFunction · 0.85

Tested by

no test coverage detected