@lmzhen/dsh-evolution-core 0.19.0 → 0.19.2
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/lib/index.js +39 -12
- package/lib/types/run-registry.d.ts +13 -3
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -6049,6 +6049,15 @@ function newRunRegistry(options) {
|
|
|
6049
6049
|
const records = [];
|
|
6050
6050
|
const controllers = /* @__PURE__ */ new Map();
|
|
6051
6051
|
const ordered = () => [...records].sort((a, b) => b.startedAt - a.startedAt);
|
|
6052
|
+
/** The ONE wording of the orphan verdict — read-time convergence says it in two places. */
|
|
6053
|
+
const ORPHAN_FAILURE = "no live owner process — the run was interrupted before it settled (orphan)";
|
|
6054
|
+
/** A `running` record whose owner is gone, as the index must show it. */
|
|
6055
|
+
const orphanOf = (record) => ({
|
|
6056
|
+
...record,
|
|
6057
|
+
state: "failed",
|
|
6058
|
+
endedAt: now(),
|
|
6059
|
+
failure: ORPHAN_FAILURE
|
|
6060
|
+
});
|
|
6052
6061
|
/** Keep every RUNNING record plus the newest terminal ones: memory and the
|
|
6053
6062
|
* index share one cap, so the two can never disagree about the history. */
|
|
6054
6063
|
const trim = () => {
|
|
@@ -6065,7 +6074,12 @@ function newRunRegistry(options) {
|
|
|
6065
6074
|
const onDisk = parseIndex(current);
|
|
6066
6075
|
const merged = /* @__PURE__ */ new Map();
|
|
6067
6076
|
for (const record of onDisk.records) merged.set(record.id, record);
|
|
6068
|
-
for (const record of records)
|
|
6077
|
+
for (const record of records) {
|
|
6078
|
+
const onDiskRow = merged.get(record.id);
|
|
6079
|
+
const settledElsewhere = onDiskRow !== void 0 && TERMINAL.has(onDiskRow.state) && !TERMINAL.has(record.state);
|
|
6080
|
+
if (!controllers.has(record.id) && settledElsewhere) continue;
|
|
6081
|
+
merged.set(record.id, record);
|
|
6082
|
+
}
|
|
6069
6083
|
const view = [...merged.values()].sort((a, b) => b.startedAt - a.startedAt);
|
|
6070
6084
|
const live = view.filter((record) => record.state === "running");
|
|
6071
6085
|
const done = view.filter((record) => TERMINAL.has(record.state)).slice(0, maxRecords);
|
|
@@ -6100,8 +6114,25 @@ function newRunRegistry(options) {
|
|
|
6100
6114
|
};
|
|
6101
6115
|
let converged = 0;
|
|
6102
6116
|
let liveElsewhere = 0;
|
|
6117
|
+
let healed = 0;
|
|
6103
6118
|
for (const record of parsed.records) {
|
|
6104
|
-
|
|
6119
|
+
const knownIndex = records.findIndex((item) => item.id === record.id);
|
|
6120
|
+
if (knownIndex >= 0) {
|
|
6121
|
+
const known = records[knownIndex];
|
|
6122
|
+
if (!controllers.has(record.id) && !TERMINAL.has(known.state)) {
|
|
6123
|
+
if (TERMINAL.has(record.state)) {
|
|
6124
|
+
delete known.endedAt;
|
|
6125
|
+
delete known.resultRef;
|
|
6126
|
+
delete known.failure;
|
|
6127
|
+
Object.assign(known, record);
|
|
6128
|
+
healed++;
|
|
6129
|
+
} else if (record.pid === void 0 || !isProcessAlive(record.pid)) {
|
|
6130
|
+
records[knownIndex] = orphanOf(record);
|
|
6131
|
+
converged++;
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
6134
|
+
continue;
|
|
6135
|
+
}
|
|
6105
6136
|
if (record.state !== "running") {
|
|
6106
6137
|
records.push(record);
|
|
6107
6138
|
continue;
|
|
@@ -6112,25 +6143,21 @@ function newRunRegistry(options) {
|
|
|
6112
6143
|
continue;
|
|
6113
6144
|
}
|
|
6114
6145
|
converged++;
|
|
6115
|
-
records.push(
|
|
6116
|
-
...record,
|
|
6117
|
-
state: "failed",
|
|
6118
|
-
endedAt: now(),
|
|
6119
|
-
failure: "no live owner process — the run was interrupted before it settled (orphan)"
|
|
6120
|
-
});
|
|
6146
|
+
records.push(orphanOf(record));
|
|
6121
6147
|
}
|
|
6122
|
-
if (converged > 0) await persist();
|
|
6148
|
+
if (converged > 0 || healed > 0) await persist();
|
|
6123
6149
|
const notes = [
|
|
6124
6150
|
parsed.note,
|
|
6125
6151
|
converged > 0 ? `${converged} run(s) with no live owner were recorded as failed(orphan)` : void 0,
|
|
6126
|
-
liveElsewhere > 0 ? `${liveElsewhere} run(s) are in flight in another process sharing this home` : void 0
|
|
6152
|
+
liveElsewhere > 0 ? `${liveElsewhere} run(s) are in flight in another process sharing this home` : void 0,
|
|
6153
|
+
healed > 0 ? `${healed} run(s) settled by their owner were re-read from the index` : void 0
|
|
6127
6154
|
].filter((note) => note !== void 0);
|
|
6128
6155
|
return {
|
|
6129
6156
|
ok: true,
|
|
6130
6157
|
...notes.length > 0 ? { note: notes.join("; ") } : {}
|
|
6131
6158
|
};
|
|
6132
6159
|
},
|
|
6133
|
-
begin(kind) {
|
|
6160
|
+
async begin(kind) {
|
|
6134
6161
|
const id = randomUUID();
|
|
6135
6162
|
const startedAt = now();
|
|
6136
6163
|
const controller = new AbortController();
|
|
@@ -6142,7 +6169,7 @@ function newRunRegistry(options) {
|
|
|
6142
6169
|
startedAt,
|
|
6143
6170
|
pid: process.pid
|
|
6144
6171
|
});
|
|
6145
|
-
persist();
|
|
6172
|
+
await persist();
|
|
6146
6173
|
return {
|
|
6147
6174
|
id,
|
|
6148
6175
|
kind,
|
|
@@ -65,13 +65,23 @@ export interface RunOutcome {
|
|
|
65
65
|
}
|
|
66
66
|
/** The registry surface the commands row drives. */
|
|
67
67
|
export interface RunRegistry {
|
|
68
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* Converge the persisted index; the commands row calls it before answering any read
|
|
70
|
+
* (0.19.1: it also re-reads a terminal state written by the run's OWNER — see the
|
|
71
|
+
* implementation note below).
|
|
72
|
+
*/
|
|
69
73
|
load(): Promise<{
|
|
70
74
|
ok: boolean;
|
|
71
75
|
note?: string;
|
|
72
76
|
}>;
|
|
73
|
-
/**
|
|
74
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Register a new run, arm its cancellation, and return its handle.
|
|
79
|
+
*
|
|
80
|
+
* Resolves only once the row is in the shared index (0.19.1, review P2): the detached
|
|
81
|
+
* lifetime starts when the caller answers "started", so a plane that reads that answer
|
|
82
|
+
* must find the run. The cost is one local index write on the ack path (milliseconds).
|
|
83
|
+
*/
|
|
84
|
+
begin(kind: RunKind): Promise<RunHandle>;
|
|
75
85
|
/** Record a run's terminal state (first writer wins). */
|
|
76
86
|
settle(id: string, outcome: RunOutcome): Promise<void>;
|
|
77
87
|
/** The live run, when there is one (one kind today — see the implementation note). */
|
package/package.json
CHANGED