om-memory-system 4.11.0-next.96 → 4.11.1

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.
@@ -20,7 +20,9 @@ export interface WebUpdateCommandDeps {
20
20
  restartLoginItem: () => boolean;
21
21
  /** Start a detached web app through the launcher. False when there is nothing to start. */
22
22
  startDetached: () => boolean;
23
- writeStartLock: () => void;
23
+ /** Take the start lock. False when another caller holds a fresh one. */
24
+ takeStartLock: () => boolean;
25
+ /** Remove the start lock, only when this process holds it. */
24
26
  removeStartLock: () => void;
25
27
  writeRetireMarker: (before: number) => void;
26
28
  print: (line: string) => void;
@@ -91,7 +91,11 @@ export async function runWebUpdate(deps) {
91
91
  deps.print(`Global install is up to date (${before}).`);
92
92
  }
93
93
  // 2. Replace every standalone web app. Hosts wait while no web app serves.
94
- deps.writeStartLock();
94
+ // A fresh lock of another caller is left alone, and so is that caller's start.
95
+ if (!deps.takeStartLock()) {
96
+ deps.print("Another start is running (a host start or another web update). Wait a few seconds, then run om-memory-system web update again.");
97
+ return finish(1, "lock-held", "lock-held");
98
+ }
95
99
  try {
96
100
  deps.writeRetireMarker(deps.now());
97
101
  const owner = await readOwner(deps);
@@ -114,13 +118,11 @@ export async function runWebUpdate(deps) {
114
118
  const deadline = deps.now() + FRESH_WAIT_MS;
115
119
  while (deps.now() < deadline) {
116
120
  const current = await readOwner(deps);
117
- if (current && !askedAside.has(current.instance)) {
118
- const older = current.version !== null && (compareVersions(current.version, deps.version) ?? 0) < 0;
119
- if (!older) {
121
+ // A web app that hides its version cannot be told from an old waiter, so keep waiting.
122
+ if (current?.version && !askedAside.has(current.instance)) {
123
+ if ((compareVersions(current.version, deps.version) ?? 0) >= 0) {
120
124
  record.served = current.version;
121
- deps.print(current.version
122
- ? `OMMS web app: ${deps.url} (version ${current.version})`
123
- : `OMMS web app: ${deps.url}`);
125
+ deps.print(`OMMS web app: ${deps.url} (version ${current.version})`);
124
126
  return finish(0, "replaced");
125
127
  }
126
128
  // An older web app that waited for the port took it before the fresh one.
@@ -138,7 +140,7 @@ export async function runWebUpdate(deps) {
138
140
  }
139
141
  /** The real network, npm, login item, and launcher. */
140
142
  export async function productionWebUpdateDeps(options) {
141
- const [{ spawn }, { existsSync }, { join }, { AUTH_HEADER, getOrCreateAuthToken }, { packageVersion }, { latestNpmVersion }, { globalCommandVersion }, { runGlobalInstall }, { nodeInstallDeps }, { restartWebAutostart, webAutostartStatus }, { launcherPath, recordedCopy }, { ommsDir }, { nodeLockFs, removeStartLockFor, startLockPath }, { writeRetireMarker }, { log },] = await Promise.all([
143
+ const [{ spawn }, { existsSync }, { join }, { AUTH_HEADER, getOrCreateAuthToken }, { packageVersion }, { latestNpmVersion }, { globalCommandVersion }, { runGlobalInstall }, { nodeInstallDeps }, { restartWebAutostart, webAutostartStatus }, { launcherPath, recordedCopy }, { ommsDir }, { nodeLockFs, processAlive, removeStartLockFor, startLockPath, takeStartLock }, { writeRetireMarker }, { log },] = await Promise.all([
142
144
  import("node:child_process"),
143
145
  import("node:fs"),
144
146
  import("node:path"),
@@ -194,7 +196,13 @@ export async function productionWebUpdateDeps(options) {
194
196
  return false;
195
197
  }
196
198
  },
197
- writeStartLock: () => nodeLockFs.replace(lockPath, JSON.stringify({ pid: process.pid, at: Date.now() })),
199
+ takeStartLock: () => takeStartLock({
200
+ lockPath,
201
+ lockFs: nodeLockFs,
202
+ pid: process.pid,
203
+ now: () => Date.now(),
204
+ pidAlive: processAlive,
205
+ }),
198
206
  removeStartLock: () => removeStartLockFor(process.pid, lockPath),
199
207
  writeRetireMarker: (before) => writeRetireMarker(before, { home: options.home }),
200
208
  print: (line) => console.log(line),
@@ -74,6 +74,7 @@ export declare const nodeLockFs: LockFs;
74
74
  export declare function renameRetrying(from: string, to: string, rename?: (from: string, to: string) => void, platform?: NodeJS.Platform, wait?: (ms: number) => void): void;
75
75
  /** Remove the start lock when it names `pid`. A restart copy calls this once it owns the port. */
76
76
  export declare function removeStartLockFor(pid: number, path?: string, lockFs?: LockFs): void;
77
+ export declare function processAlive(pid: number): boolean;
77
78
  /** What taking the start lock needs; a test drives two callers through it step by step. */
78
79
  export type LockDeps = Pick<EnsureDeps, "lockPath" | "lockFs" | "pid" | "now" | "pidAlive">;
79
80
  /**
@@ -111,7 +111,7 @@ export function removeStartLockFor(pid, path = startLockPath(), lockFs = nodeLoc
111
111
  /* An unreadable lock is stale and the next caller replaces it. */
112
112
  }
113
113
  }
114
- function processAlive(pid) {
114
+ export function processAlive(pid) {
115
115
  try {
116
116
  process.kill(pid, 0);
117
117
  return true;