@remit/doctor 0.0.1 → 0.0.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/package.json +1 -1
- package/src/cli.ts +5 -1
- package/src/index.ts +1 -0
- package/src/report.test.ts +59 -1
- package/src/report.ts +23 -0
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
NO_VERDICT_EXIT_CODE,
|
|
7
7
|
renderJson,
|
|
8
8
|
renderLines,
|
|
9
|
+
writeVerdict,
|
|
9
10
|
} from "./report.js";
|
|
10
11
|
import { readState } from "./state.js";
|
|
11
12
|
|
|
@@ -31,7 +32,10 @@ const check = async (): Promise<number> => {
|
|
|
31
32
|
setLogLevel(config.logLevel);
|
|
32
33
|
const state = await readState(config.stateDir);
|
|
33
34
|
const result = await runCheck(config, state.counters);
|
|
34
|
-
|
|
35
|
+
await writeVerdict(
|
|
36
|
+
process.stdout,
|
|
37
|
+
json ? renderJson(result) : renderLines(result),
|
|
38
|
+
);
|
|
35
39
|
return exitCodeFor(result);
|
|
36
40
|
};
|
|
37
41
|
|
package/src/index.ts
CHANGED
package/src/report.test.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { describe, it } from "node:test";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
exitCodeFor,
|
|
5
|
+
renderJson,
|
|
6
|
+
renderLines,
|
|
7
|
+
writeVerdict,
|
|
8
|
+
} from "./report.js";
|
|
4
9
|
import type { CheckResult } from "./verdict.js";
|
|
5
10
|
|
|
6
11
|
const degraded: CheckResult = {
|
|
@@ -163,3 +168,56 @@ describe("exit codes", () => {
|
|
|
163
168
|
assert.equal(exitCodeFor(degraded), 1);
|
|
164
169
|
});
|
|
165
170
|
});
|
|
171
|
+
|
|
172
|
+
describe("writeVerdict", () => {
|
|
173
|
+
// The whole point: `process.exit` discards a write the kernel could not
|
|
174
|
+
// take, so the verdict has to be out of the process before the code is
|
|
175
|
+
// returned. A stream that reports back-pressure and drains later is what a
|
|
176
|
+
// pipe under `compose exec -T` does with a long degraded verdict.
|
|
177
|
+
const backPressured = () => {
|
|
178
|
+
const chunks: string[] = [];
|
|
179
|
+
let drain: (() => void) | undefined;
|
|
180
|
+
return {
|
|
181
|
+
chunks,
|
|
182
|
+
release: () => drain?.(),
|
|
183
|
+
stream: {
|
|
184
|
+
write(text: string) {
|
|
185
|
+
chunks.push(text);
|
|
186
|
+
return false;
|
|
187
|
+
},
|
|
188
|
+
once(event: string, listener: () => void) {
|
|
189
|
+
if (event === "drain") drain = listener;
|
|
190
|
+
return this;
|
|
191
|
+
},
|
|
192
|
+
} as unknown as NodeJS.WritableStream,
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
it("does not resolve until the stream drains", async () => {
|
|
197
|
+
const sink = backPressured();
|
|
198
|
+
let settled = false;
|
|
199
|
+
const done = writeVerdict(sink.stream, renderLines(degraded)).then(() => {
|
|
200
|
+
settled = true;
|
|
201
|
+
});
|
|
202
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
203
|
+
assert.equal(settled, false, "resolved before the stream drained");
|
|
204
|
+
sink.release();
|
|
205
|
+
await done;
|
|
206
|
+
assert.equal(sink.chunks.join(""), renderLines(degraded));
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("resolves straight away when the write was taken", async () => {
|
|
210
|
+
const chunks: string[] = [];
|
|
211
|
+
const stream = {
|
|
212
|
+
write(text: string) {
|
|
213
|
+
chunks.push(text);
|
|
214
|
+
return true;
|
|
215
|
+
},
|
|
216
|
+
once() {
|
|
217
|
+
assert.fail("waited on drain after a write that was taken");
|
|
218
|
+
},
|
|
219
|
+
} as unknown as NodeJS.WritableStream;
|
|
220
|
+
await writeVerdict(stream, renderJson(healthy));
|
|
221
|
+
assert.equal(chunks.join(""), renderJson(healthy));
|
|
222
|
+
});
|
|
223
|
+
});
|
package/src/report.ts
CHANGED
|
@@ -104,3 +104,26 @@ export const exitCodeFor = (result: CheckResult): number =>
|
|
|
104
104
|
result.verdict === "healthy" ? 0 : 1;
|
|
105
105
|
|
|
106
106
|
export const NO_VERDICT_EXIT_CODE = 2;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The verdict has to have left the process before it exits.
|
|
110
|
+
*
|
|
111
|
+
* `process.exit` does not flush a pending write, and stdout is a pipe under
|
|
112
|
+
* `compose exec -T`, so a write the kernel could not take in one go is
|
|
113
|
+
* discarded — silently, and only for the verdicts long enough to fill the
|
|
114
|
+
* buffer, which are the degraded ones carrying several reasons. The reader
|
|
115
|
+
* then sees a document that stops mid-token with an exit code saying it is
|
|
116
|
+
* complete. Waiting for the drain and keeping the explicit exit is what closes
|
|
117
|
+
* that without letting a lingering socket hold the process open instead.
|
|
118
|
+
*/
|
|
119
|
+
export const writeVerdict = (
|
|
120
|
+
stream: NodeJS.WritableStream,
|
|
121
|
+
text: string,
|
|
122
|
+
): Promise<void> =>
|
|
123
|
+
new Promise((resolve) => {
|
|
124
|
+
if (stream.write(text)) {
|
|
125
|
+
resolve();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
stream.once("drain", () => resolve());
|
|
129
|
+
});
|