@primafuture/systemd-tasks 1.0.0 → 1.2.0
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/CHANGELOG.md +40 -0
- package/README.md +141 -8
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/finalizer.mjs +448 -0
- package/dist/finalizer.mjs.map +1 -0
- package/dist/guardian.mjs +212 -0
- package/dist/guardian.mjs.map +1 -0
- package/dist/index.cjs +9 -13287
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -316
- package/dist/index.d.ts +1 -316
- package/dist/index.mjs +2 -13304
- package/dist/index.mjs.map +1 -1
- package/dist/observed.cjs +35 -0
- package/dist/observed.cjs.map +1 -0
- package/dist/observed.d.cts +1 -0
- package/dist/observed.d.ts +1 -0
- package/dist/observed.mjs +8 -0
- package/dist/observed.mjs.map +1 -0
- package/dist/runtime.cjs +14382 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +487 -0
- package/docs/implementation-decisions.md +137 -0
- package/package.json +27 -7
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// src/guardian.ts
|
|
2
|
+
import * as childProcess from "child_process";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as net from "net";
|
|
5
|
+
|
|
6
|
+
// src/observed-framing.ts
|
|
7
|
+
var magic = Buffer.from("SDTO", "ascii");
|
|
8
|
+
var version = 1;
|
|
9
|
+
var headerBytes = 10;
|
|
10
|
+
var maximumPayloadBytes = 64 * 1024;
|
|
11
|
+
var kind = Object.freeze({ ready: 1, stdout: 2, stderr: 3, complete: 4 });
|
|
12
|
+
function encode(frameKind, payload = new Uint8Array()) {
|
|
13
|
+
if (!Object.values(kind).includes(frameKind) || payload.byteLength > maximumPayloadBytes) throw new Error("Invalid observed guardian frame.");
|
|
14
|
+
const frame = Buffer.allocUnsafe(headerBytes + payload.byteLength);
|
|
15
|
+
magic.copy(frame, 0);
|
|
16
|
+
frame[4] = version;
|
|
17
|
+
frame[5] = frameKind;
|
|
18
|
+
frame.writeUInt32BE(payload.byteLength, 6);
|
|
19
|
+
frame.set(payload, headerBytes);
|
|
20
|
+
return frame;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/guardian.ts
|
|
24
|
+
function fail(message, cause) {
|
|
25
|
+
throw new Error(`Observed task guardian failed: ${message}`, cause === void 0 ? void 0 : { cause });
|
|
26
|
+
}
|
|
27
|
+
function validateDescriptors() {
|
|
28
|
+
if (process.env.LISTEN_PID !== String(process.pid)) fail("LISTEN_PID does not identify this process.");
|
|
29
|
+
if (process.env.LISTEN_FDS !== "3") fail("LISTEN_FDS is not exactly three.");
|
|
30
|
+
if (process.env.LISTEN_FDNAMES !== "task-stdout:task-stderr:observer") fail("LISTEN_FDNAMES has an unexpected order.");
|
|
31
|
+
for (const descriptor of [3, 4, 5]) if (!fs.fstatSync(descriptor).isSocket()) fail(`descriptor ${descriptor} is not a socket.`);
|
|
32
|
+
delete process.env.LISTEN_PID;
|
|
33
|
+
delete process.env.LISTEN_FDS;
|
|
34
|
+
delete process.env.LISTEN_FDNAMES;
|
|
35
|
+
}
|
|
36
|
+
function notifyReady() {
|
|
37
|
+
const result = childProcess.spawnSync("/usr/bin/systemd-notify", ["--ready", "--pid=parent"], {
|
|
38
|
+
env: process.env,
|
|
39
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
40
|
+
encoding: "utf8",
|
|
41
|
+
timeout: 5e3
|
|
42
|
+
});
|
|
43
|
+
if (result.error) fail("systemd-notify could not execute.", result.error);
|
|
44
|
+
if (result.status !== 0) fail(`systemd-notify exited with status ${String(result.status)}.`);
|
|
45
|
+
}
|
|
46
|
+
function payloadWasInvoked(unitName) {
|
|
47
|
+
if (process.getuid === void 0) return null;
|
|
48
|
+
const runtimeDirectory = `/run/user/${String(process.getuid())}`;
|
|
49
|
+
const result = childProcess.spawnSync("/usr/bin/systemctl", ["--user", "show", unitName, "--property=InvocationID", "--value"], {
|
|
50
|
+
env: { XDG_RUNTIME_DIR: runtimeDirectory, DBUS_SESSION_BUS_ADDRESS: `unix:path=${runtimeDirectory}/bus` },
|
|
51
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
52
|
+
encoding: "utf8",
|
|
53
|
+
timeout: 5e3,
|
|
54
|
+
maxBuffer: 4096
|
|
55
|
+
});
|
|
56
|
+
if (result.error || result.status !== 0) return null;
|
|
57
|
+
const invocationId = result.stdout.trim();
|
|
58
|
+
if (invocationId === "") return false;
|
|
59
|
+
return /^[0-9a-f]{32}$/.test(invocationId) ? true : null;
|
|
60
|
+
}
|
|
61
|
+
async function writeReady(observer) {
|
|
62
|
+
return await new Promise(
|
|
63
|
+
/** Chyba client-facing socketu znamená detach, nikoliv selhání guardian infrastruktury. */
|
|
64
|
+
(resolve) => {
|
|
65
|
+
try {
|
|
66
|
+
observer.write(encode(kind.ready), (error) => {
|
|
67
|
+
resolve(error === void 0 || error === null);
|
|
68
|
+
});
|
|
69
|
+
} catch {
|
|
70
|
+
resolve(false);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
async function run() {
|
|
76
|
+
validateDescriptors();
|
|
77
|
+
const payloadUnitName = process.argv[2];
|
|
78
|
+
if (!payloadUnitName || !/^pf-systemd-tasks-observed-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\.service$/.test(payloadUnitName)) fail("payload unit name is invalid.");
|
|
79
|
+
const stdout = new net.Socket({ fd: 3, readable: true, writable: false });
|
|
80
|
+
const stderr = new net.Socket({ fd: 4, readable: true, writable: false });
|
|
81
|
+
const observer = new net.Socket({ fd: 5, readable: true, writable: true, allowHalfOpen: true });
|
|
82
|
+
const sources = [
|
|
83
|
+
{ stream: stdout, kind: kind.stdout, ended: false, pending: null },
|
|
84
|
+
{ stream: stderr, kind: kind.stderr, ended: false, pending: null }
|
|
85
|
+
];
|
|
86
|
+
let attached = true;
|
|
87
|
+
let blocked = false;
|
|
88
|
+
let pumping = false;
|
|
89
|
+
let finishing = false;
|
|
90
|
+
let nextSourceIndex = 0;
|
|
91
|
+
let readyFrameSettled = false;
|
|
92
|
+
function detach() {
|
|
93
|
+
if (!attached) return;
|
|
94
|
+
attached = false;
|
|
95
|
+
blocked = false;
|
|
96
|
+
observer.destroy();
|
|
97
|
+
for (const source of sources) {
|
|
98
|
+
source.pending = null;
|
|
99
|
+
source.stream.off("readable", pump);
|
|
100
|
+
source.stream.resume();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function finishIfComplete() {
|
|
104
|
+
if (!readyFrameSettled || finishing || !sources.every(
|
|
105
|
+
/** Oba payload descriptory musí potvrdit EOF. */
|
|
106
|
+
(source) => source.ended
|
|
107
|
+
)) return;
|
|
108
|
+
finishing = true;
|
|
109
|
+
if (!attached) process.exit(0);
|
|
110
|
+
observer.end(
|
|
111
|
+
encode(kind.complete),
|
|
112
|
+
/** Lokální shutdown callback potvrzuje odeslaný FIN bez čekání na vzdálený close. */
|
|
113
|
+
() => process.exit(0)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
function pump() {
|
|
117
|
+
if (pumping || blocked || !readyFrameSettled) return;
|
|
118
|
+
pumping = true;
|
|
119
|
+
try {
|
|
120
|
+
let idleSources = 0;
|
|
121
|
+
while (!blocked && idleSources < sources.length) {
|
|
122
|
+
const source = sources[nextSourceIndex];
|
|
123
|
+
nextSourceIndex = (nextSourceIndex + 1) % sources.length;
|
|
124
|
+
const available = source.pending ?? source.stream.read();
|
|
125
|
+
if (available === null) {
|
|
126
|
+
idleSources++;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
idleSources = 0;
|
|
130
|
+
const chunk = available.subarray(0, maximumPayloadBytes);
|
|
131
|
+
source.pending = available.byteLength > chunk.byteLength ? available.subarray(chunk.byteLength) : null;
|
|
132
|
+
if (attached) {
|
|
133
|
+
const writable = observer.write(encode(source.kind, chunk));
|
|
134
|
+
if (attached && !writable) blocked = true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
} finally {
|
|
138
|
+
pumping = false;
|
|
139
|
+
}
|
|
140
|
+
finishIfComplete();
|
|
141
|
+
}
|
|
142
|
+
function sourceFailure(error) {
|
|
143
|
+
stdout.destroy();
|
|
144
|
+
stderr.destroy();
|
|
145
|
+
observer.destroy();
|
|
146
|
+
process.nextTick(
|
|
147
|
+
/** Throw mimo EventEmitter callback zachová nenulový process exit. */
|
|
148
|
+
() => {
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
for (const source of sources) {
|
|
154
|
+
source.stream.on("readable", pump);
|
|
155
|
+
source.stream.once(
|
|
156
|
+
"end",
|
|
157
|
+
/** Drain zbytku před terminal EOF. */
|
|
158
|
+
() => {
|
|
159
|
+
source.ended = true;
|
|
160
|
+
pump();
|
|
161
|
+
finishIfComplete();
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
source.stream.once("error", sourceFailure);
|
|
165
|
+
}
|
|
166
|
+
observer.on(
|
|
167
|
+
"drain",
|
|
168
|
+
/** Pokračuje až po skutečném poklesu Node write fronty. */
|
|
169
|
+
() => {
|
|
170
|
+
blocked = false;
|
|
171
|
+
pump();
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
observer.on(
|
|
175
|
+
"data",
|
|
176
|
+
/** Protokol je jednosměrný; neočekávaný klientský payload znamená detach. */
|
|
177
|
+
detach
|
|
178
|
+
);
|
|
179
|
+
observer.once("end", detach);
|
|
180
|
+
observer.once("close", detach);
|
|
181
|
+
observer.once("error", detach);
|
|
182
|
+
process.on(
|
|
183
|
+
"SIGTERM",
|
|
184
|
+
/** Jen pre-exec cancellation postrádá skutečné EOF, protože manager dál vlastní write endpointy. */
|
|
185
|
+
() => {
|
|
186
|
+
if (payloadWasInvoked(payloadUnitName) !== false) {
|
|
187
|
+
pump();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
for (const source of sources) {
|
|
191
|
+
source.ended = true;
|
|
192
|
+
source.pending = null;
|
|
193
|
+
source.stream.destroy();
|
|
194
|
+
}
|
|
195
|
+
finishIfComplete();
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
notifyReady();
|
|
199
|
+
if (!await writeReady(observer)) detach();
|
|
200
|
+
readyFrameSettled = true;
|
|
201
|
+
if (attached) observer.resume();
|
|
202
|
+
pump();
|
|
203
|
+
}
|
|
204
|
+
void run().catch(
|
|
205
|
+
/** Top-level startup failure musí zachovat nenulový guardian exit. */
|
|
206
|
+
(error) => {
|
|
207
|
+
process.nextTick(() => {
|
|
208
|
+
throw error;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
//# sourceMappingURL=guardian.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/guardian.ts","../src/observed-framing.ts"],"sourcesContent":["import * as childProcess from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as net from 'node:net';\nimport * as framing from './observed-framing';\n\n/** Jeden guardian input drží svůj framing kind a případný zbytek velkého stream readu. */\ninterface Source {\n\t/** Raw task stream vlastněný tímto guardian procesem. */\n\treadonly stream: net.Socket;\n\t/** Output kind zachovávající oddělení stdout a stderr. */\n\treadonly kind: typeof framing.kind.stdout | typeof framing.kind.stderr;\n\t/** EOF je autoritativní až po vyčerpání kernel bufferu. */\n\tended: boolean;\n\t/** Zbytek většího readu čekající na další bounded frame. */\n\tpending: Buffer | null;\n}\n\n/** Ukončí guardian fail-closed bez zápisu citlivých output dat na jeho stdio. */\nfunction fail(message: string, cause?: unknown): never {\n\tthrow new Error(`Observed task guardian failed: ${message}`, cause === undefined ? undefined : { cause });\n}\n\n/** Ověří přesný systemd fd-store kontrakt dřív, než guardian oznámí readiness. */\nfunction validateDescriptors(): void {\n\tif (process.env.LISTEN_PID !== String(process.pid)) fail('LISTEN_PID does not identify this process.');\n\tif (process.env.LISTEN_FDS !== '3') fail('LISTEN_FDS is not exactly three.');\n\tif (process.env.LISTEN_FDNAMES !== 'task-stdout:task-stderr:observer') fail('LISTEN_FDNAMES has an unexpected order.');\n\tfor (const descriptor of [3, 4, 5]) if (!fs.fstatSync(descriptor).isSocket()) fail(`descriptor ${descriptor} is not a socket.`);\n\tdelete process.env.LISTEN_PID;\n\tdelete process.env.LISTEN_FDS;\n\tdelete process.env.LISTEN_FDNAMES;\n}\n\n/** Potvrdí systemd readiness synchronně, aby ready frame nikdy nepředběhl selhání notify. */\nfunction notifyReady(): void {\n\tconst result = childProcess.spawnSync('/usr/bin/systemd-notify', ['--ready', '--pid=parent'], {\n\t\tenv: process.env,\n\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\tencoding: 'utf8',\n\t\ttimeout: 5000,\n\t});\n\tif (result.error) fail('systemd-notify could not execute.', result.error);\n\tif (result.status !== 0) fail(`systemd-notify exited with status ${String(result.status)}.`);\n}\n\n/** Přečte payload InvocationID až po ordered stopu; prázdná hodnota spolehlivě značí zrušení před exec. */\nfunction payloadWasInvoked(unitName: string): boolean | null {\n\tif (process.getuid === undefined) return null;\n\tconst runtimeDirectory = `/run/user/${String(process.getuid())}`;\n\tconst result = childProcess.spawnSync('/usr/bin/systemctl', ['--user', 'show', unitName, '--property=InvocationID', '--value'], {\n\t\tenv: { XDG_RUNTIME_DIR: runtimeDirectory, DBUS_SESSION_BUS_ADDRESS: `unix:path=${runtimeDirectory}/bus` },\n\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\tencoding: 'utf8',\n\t\ttimeout: 5000,\n\t\tmaxBuffer: 4096,\n\t});\n\tif (result.error || result.status !== 0) return null;\n\tconst invocationId = result.stdout.trim();\n\tif (invocationId === '') return false;\n\treturn /^[0-9a-f]{32}$/.test(invocationId) ? true : null;\n}\n\n/** Rozliší lokální acceptance ready frame od observeru odpojeného během startupu. */\nasync function writeReady(observer: net.Socket): Promise<boolean> {\n\treturn await new Promise<boolean>(/** Chyba client-facing socketu znamená detach, nikoliv selhání guardian infrastruktury. */ resolve => {\n\t\ttry { observer.write(framing.encode(framing.kind.ready), error => { resolve(error === undefined || error === null); }); }\n\t\tcatch { resolve(false); }\n\t});\n}\n\n/** Drží output pipes průchozí po detach a končí až po EOF obou payload kanálů. */\nasync function run(): Promise<void> {\n\tvalidateDescriptors();\n\tconst payloadUnitName = process.argv[2];\n\tif (!payloadUnitName || !/^pf-systemd-tasks-observed-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\\.service$/.test(payloadUnitName)) fail('payload unit name is invalid.');\n\tconst stdout = new net.Socket({ fd: 3, readable: true, writable: false });\n\tconst stderr = new net.Socket({ fd: 4, readable: true, writable: false });\n\tconst observer = new net.Socket({ fd: 5, readable: true, writable: true, allowHalfOpen: true });\n\tconst sources: Source[] = [\n\t\t{ stream: stdout, kind: framing.kind.stdout, ended: false, pending: null },\n\t\t{ stream: stderr, kind: framing.kind.stderr, ended: false, pending: null },\n\t];\n\tlet attached = true;\n\tlet blocked = false;\n\tlet pumping = false;\n\tlet finishing = false;\n\tlet nextSourceIndex = 0;\n\tlet readyFrameSettled = false;\n\n\t/** Přepne nevratně do drain/discard a uvolní output backpressure payloadu. */\n\tfunction detach(): void {\n\t\tif (!attached) return;\n\t\tattached = false;\n\t\tblocked = false;\n\t\tobserver.destroy();\n\t\tfor (const source of sources) {\n\t\t\tsource.pending = null;\n\t\t\tsource.stream.off('readable', pump);\n\t\t\tsource.stream.resume();\n\t\t}\n\t}\n\n\t/** Po obou EOF odešle jediný complete frame, nebo po detach prostě dovolí exit. */\n\tfunction finishIfComplete(): void {\n\t\tif (!readyFrameSettled || finishing || !sources.every(/** Oba payload descriptory musí potvrdit EOF. */ source => source.ended)) return;\n\t\tfinishing = true;\n\t\tif (!attached) process.exit(0);\n\t\tobserver.end(framing.encode(framing.kind.complete), /** Lokální shutdown callback potvrzuje odeslaný FIN bez čekání na vzdálený close. */ () => process.exit(0));\n\t}\n\n\t/** Fair round-robin čte nejvýše bounded framy a respektuje skutečné EOF i observer write backpressure. */\n\tfunction pump(): void {\n\t\tif (pumping || blocked || !readyFrameSettled) return;\n\t\tpumping = true;\n\t\ttry {\n\t\t\tlet idleSources = 0;\n\t\t\twhile (!blocked && idleSources < sources.length) {\n\t\t\t\tconst source = sources[nextSourceIndex]!;\n\t\t\t\tnextSourceIndex = (nextSourceIndex + 1) % sources.length;\n\t\t\t\tconst available = source.pending ?? source.stream.read();\n\t\t\t\tif (available === null) { idleSources++; continue; }\n\t\t\t\tidleSources = 0;\n\t\t\t\tconst chunk = available.subarray(0, framing.maximumPayloadBytes);\n\t\t\t\tsource.pending = available.byteLength > chunk.byteLength ? available.subarray(chunk.byteLength) : null;\n\t\t\t\tif (attached) {\n\t\t\t\t\tconst writable = observer.write(framing.encode(source.kind, chunk));\n\t\t\t\t\tif (attached && !writable) blocked = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} finally { pumping = false; }\n\t\tfinishIfComplete();\n\t}\n\n\t/** Zdrojová chyba musí shodit guardian a přes BindsTo fail-closed zastavit payload. */\n\tfunction sourceFailure(error: Error): void {\n\t\tstdout.destroy();\n\t\tstderr.destroy();\n\t\tobserver.destroy();\n\t\tprocess.nextTick(/** Throw mimo EventEmitter callback zachová nenulový process exit. */ () => { throw error; });\n\t}\n\n\tfor (const source of sources) {\n\t\tsource.stream.on('readable', pump);\n\t\tsource.stream.once('end', /** Drain zbytku před terminal EOF. */ () => { source.ended = true; pump(); finishIfComplete(); });\n\t\tsource.stream.once('error', sourceFailure);\n\t}\n\tobserver.on('drain', /** Pokračuje až po skutečném poklesu Node write fronty. */ () => { blocked = false; pump(); });\n\tobserver.on('data', /** Protokol je jednosměrný; neočekávaný klientský payload znamená detach. */ detach);\n\tobserver.once('end', detach);\n\tobserver.once('close', detach);\n\tobserver.once('error', detach);\n\tprocess.on('SIGTERM', /** Jen pre-exec cancellation postrádá skutečné EOF, protože manager dál vlastní write endpointy. */ () => {\n\t\tif (payloadWasInvoked(payloadUnitName) !== false) { pump(); return; }\n\t\tfor (const source of sources) {\n\t\t\tsource.ended = true;\n\t\t\tsource.pending = null;\n\t\t\tsource.stream.destroy();\n\t\t}\n\t\tfinishIfComplete();\n\t});\n\n\tnotifyReady();\n\tif (!await writeReady(observer)) detach();\n\treadyFrameSettled = true;\n\tif (attached) observer.resume();\n\tpump();\n}\n\nvoid run().catch(/** Top-level startup failure musí zachovat nenulový guardian exit. */ error => { process.nextTick(() => { throw error; }); });\n","/** Čtyřbytový magic odděluje guardian stream od náhodného nebo staršího protokolu. */\nexport const magic = Buffer.from('SDTO', 'ascii');\n/** První veřejně implementovaná verze interního guardian protokolu. */\nexport const version = 1;\n/** Fixní hlavička obsahuje magic, verzi, kind a uint32be délku. */\nexport const headerBytes = 10;\n/** Jeden payload frame je bounded nezávisle na Node stream high-water marku. */\nexport const maximumPayloadBytes = 64 * 1024;\n\n/** Wire hodnoty jsou stabilní a nesmějí záviset na pořadí TypeScript enumu. */\nexport const kind = Object.freeze({ ready: 1, stdout: 2, stderr: 3, complete: 4 } as const);\n\n/** Zakóduje jeden již bounded frame pro guardian write frontu. */\nexport function encode(frameKind: number, payload: Uint8Array = new Uint8Array()): Buffer {\n\tif (!Object.values(kind).includes(frameKind as 1 | 2 | 3 | 4) || payload.byteLength > maximumPayloadBytes) throw new Error('Invalid observed guardian frame.');\n\tconst frame = Buffer.allocUnsafe(headerBytes + payload.byteLength);\n\tmagic.copy(frame, 0);\n\tframe[4] = version;\n\tframe[5] = frameKind;\n\tframe.writeUInt32BE(payload.byteLength, 6);\n\tframe.set(payload, headerBytes);\n\treturn frame;\n}\n"],"mappings":"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","names":[]}
|