start-command 0.30.2 → 0.30.3
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 +6 -0
- package/package.json +1 -1
- package/src/lib/status-formatter.js +53 -15
- package/test/session-name-status.js +59 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -62,6 +62,23 @@ function inspectDockerState(sessionName) {
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
function isDetachedDockerRecord(record) {
|
|
66
|
+
const opts = record.options || {};
|
|
67
|
+
return (
|
|
68
|
+
opts.isolated === 'docker' &&
|
|
69
|
+
opts.isolationMode === 'detached' &&
|
|
70
|
+
Boolean(opts.sessionName)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function readDockerState(record) {
|
|
75
|
+
const opts = record.options || {};
|
|
76
|
+
if (opts.isolated !== 'docker' || !opts.sessionName) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return inspectDockerState(opts.sessionName);
|
|
80
|
+
}
|
|
81
|
+
|
|
65
82
|
/**
|
|
66
83
|
* Best-effort terminal exit code reported by the isolation backend itself
|
|
67
84
|
* (currently docker via `docker inspect .State.ExitCode`). Returns null when
|
|
@@ -71,21 +88,23 @@ function inspectDockerState(sessionName) {
|
|
|
71
88
|
* @returns {number|null}
|
|
72
89
|
*/
|
|
73
90
|
function readBackendExitCode(record) {
|
|
74
|
-
const
|
|
75
|
-
if (opts.isolated !== 'docker' || !opts.sessionName) {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
const state = inspectDockerState(opts.sessionName);
|
|
91
|
+
const state = readDockerState(record);
|
|
79
92
|
return state && !state.running ? state.exitCode : null;
|
|
80
93
|
}
|
|
81
94
|
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
95
|
+
function resolveOomExitCode(footerExit, dockerState) {
|
|
96
|
+
if (footerExit !== null && footerExit !== undefined) {
|
|
97
|
+
return footerExit;
|
|
98
|
+
}
|
|
99
|
+
if (
|
|
100
|
+
dockerState &&
|
|
101
|
+
dockerState.exitCode !== null &&
|
|
102
|
+
dockerState.exitCode !== undefined &&
|
|
103
|
+
(!dockerState.running || dockerState.exitCode !== 0)
|
|
104
|
+
) {
|
|
105
|
+
return dockerState.exitCode;
|
|
86
106
|
}
|
|
87
|
-
|
|
88
|
-
return state ? state.oomKilled : null;
|
|
107
|
+
return 137;
|
|
89
108
|
}
|
|
90
109
|
|
|
91
110
|
/**
|
|
@@ -172,8 +191,15 @@ function readExitCodeFromLog(logPath) {
|
|
|
172
191
|
* @returns {Object} Possibly updated execution record
|
|
173
192
|
*/
|
|
174
193
|
function enrichDetachedStatus(record) {
|
|
175
|
-
const alive = isDetachedSessionAlive(record);
|
|
176
194
|
const footerExit = readExitCodeFromLog(record.logPath);
|
|
195
|
+
const dockerState = isDetachedDockerRecord(record)
|
|
196
|
+
? readDockerState(record)
|
|
197
|
+
: null;
|
|
198
|
+
const alive = isDetachedDockerRecord(record)
|
|
199
|
+
? dockerState === null
|
|
200
|
+
? null
|
|
201
|
+
: dockerState.running
|
|
202
|
+
: isDetachedSessionAlive(record);
|
|
177
203
|
|
|
178
204
|
// Create a shallow copy to avoid mutating the original
|
|
179
205
|
const cloneRecord = () => {
|
|
@@ -182,6 +208,19 @@ function enrichDetachedStatus(record) {
|
|
|
182
208
|
return enriched;
|
|
183
209
|
};
|
|
184
210
|
|
|
211
|
+
if (record.oomKilled === true || dockerState?.oomKilled === true) {
|
|
212
|
+
const enriched = cloneRecord();
|
|
213
|
+
enriched.oomKilled = true;
|
|
214
|
+
enriched.status = 'executed';
|
|
215
|
+
if (enriched.exitCode === null || enriched.exitCode === undefined) {
|
|
216
|
+
enriched.exitCode = resolveOomExitCode(footerExit, dockerState);
|
|
217
|
+
}
|
|
218
|
+
if (!enriched.endTime) {
|
|
219
|
+
enriched.endTime = new Date().toISOString();
|
|
220
|
+
}
|
|
221
|
+
return enriched;
|
|
222
|
+
}
|
|
223
|
+
|
|
185
224
|
if (alive === null) {
|
|
186
225
|
// Liveness is unknown: the backend could not be probed (e.g. a detached
|
|
187
226
|
// docker container that is not visible yet on a slow Docker-in-Docker host,
|
|
@@ -204,9 +243,8 @@ function enrichDetachedStatus(record) {
|
|
|
204
243
|
}
|
|
205
244
|
|
|
206
245
|
const enriched = cloneRecord();
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
enriched.oomKilled = oomKilled;
|
|
246
|
+
if (dockerState?.oomKilled !== null && dockerState?.oomKilled !== undefined) {
|
|
247
|
+
enriched.oomKilled = dockerState.oomKilled;
|
|
210
248
|
}
|
|
211
249
|
|
|
212
250
|
if (alive && enriched.status === 'executed') {
|
|
@@ -677,6 +677,65 @@ describe('Issue #144: detached docker OOMKilled status signal', () => {
|
|
|
677
677
|
});
|
|
678
678
|
});
|
|
679
679
|
|
|
680
|
+
describe('Issue #148: detached docker OOMKilled terminal status', () => {
|
|
681
|
+
let store;
|
|
682
|
+
|
|
683
|
+
beforeEach(() => {
|
|
684
|
+
cleanupTestDir();
|
|
685
|
+
store = new ExecutionStore({
|
|
686
|
+
appFolder: TEST_APP_FOLDER,
|
|
687
|
+
useLinks: false,
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
afterEach(() => {
|
|
692
|
+
cleanupTestDir();
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
function saveDockerRecord() {
|
|
696
|
+
const record = new ExecutionRecord({
|
|
697
|
+
command: 'sh -c "allocate memory"',
|
|
698
|
+
logPath: '/tmp/issue-148.log',
|
|
699
|
+
options: {
|
|
700
|
+
sessionName: 'issue148-oom',
|
|
701
|
+
isolated: 'docker',
|
|
702
|
+
isolationMode: 'detached',
|
|
703
|
+
},
|
|
704
|
+
});
|
|
705
|
+
store.save(record);
|
|
706
|
+
return record;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
it('treats oomKilled as terminal even while Docker still reports running', () => {
|
|
710
|
+
const record = saveDockerRecord();
|
|
711
|
+
|
|
712
|
+
withFakeDockerInspect('true 137 true', () => {
|
|
713
|
+
const result = queryStatus(store, record.uuid, 'json');
|
|
714
|
+
expect(result.success).toBe(true);
|
|
715
|
+
const parsed = JSON.parse(result.output);
|
|
716
|
+
expect(parsed.status).toBe('executed');
|
|
717
|
+
expect(parsed.exitCode).toBe(137);
|
|
718
|
+
expect(parsed.oomKilled).toBe(true);
|
|
719
|
+
expect(parsed.endTime).toBeTruthy();
|
|
720
|
+
expect(parsed.currentTime).toBeUndefined();
|
|
721
|
+
});
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
it('uses 137 when oomKilled is terminal but Docker has no terminal exit code yet', () => {
|
|
725
|
+
const record = saveDockerRecord();
|
|
726
|
+
|
|
727
|
+
withFakeDockerInspect('true 0 true', () => {
|
|
728
|
+
const result = queryStatus(store, record.uuid, 'json');
|
|
729
|
+
expect(result.success).toBe(true);
|
|
730
|
+
const parsed = JSON.parse(result.output);
|
|
731
|
+
expect(parsed.status).toBe('executed');
|
|
732
|
+
expect(parsed.exitCode).toBe(137);
|
|
733
|
+
expect(parsed.oomKilled).toBe(true);
|
|
734
|
+
expect(parsed.endTime).toBeTruthy();
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
|
|
680
739
|
describe('Issue #105: attachCurrentTime for executing status', () => {
|
|
681
740
|
it('should add currentTime to serialization when status is executing', () => {
|
|
682
741
|
const record = new ExecutionRecord({
|