71 lines
3.4 KiB
JavaScript
71 lines
3.4 KiB
JavaScript
export const SERVER_JOB_FAULT_SCHEMA = 1;
|
|
export const SERVER_JOB_FAULT_CODES = Object.freeze({
|
|
SUCCEEDED: "SERVER_JOB_SUCCEEDED",
|
|
CANCELLED: "SERVER_JOB_CANCELLED",
|
|
TIMEOUT: "SERVER_JOB_TIMEOUT",
|
|
OOM: "SERVER_JOB_OOM",
|
|
SIGNAL: "SERVER_JOB_SIGNAL",
|
|
EXIT_FAILED: "SERVER_JOB_EXIT_FAILED",
|
|
});
|
|
|
|
function invalid(message) {
|
|
throw new Error(`SERVER_JOB_FAULT_INVALID: ${message}`);
|
|
}
|
|
|
|
function revision(value, field) {
|
|
if (!Number.isSafeInteger(value) || value < 0) invalid(`${field} must be a non-negative revision`);
|
|
return value;
|
|
}
|
|
|
|
function optionalBoolean(value, field) {
|
|
if (value !== undefined && typeof value !== "boolean") invalid(`${field} must be boolean`);
|
|
return value === true;
|
|
}
|
|
|
|
export function classifyServerJobFault(value) {
|
|
if (!value || typeof value !== "object") invalid("input is invalid");
|
|
const cancelRequested = optionalBoolean(value.cancelRequested, "cancelRequested");
|
|
const timedOut = optionalBoolean(value.timedOut, "timedOut");
|
|
const oom = optionalBoolean(value.oom, "oom");
|
|
const memoryLimitBytes = value.memoryLimitBytes === undefined ? null : revision(value.memoryLimitBytes, "memoryLimitBytes");
|
|
const memoryBytes = value.memoryBytes === undefined ? null : revision(value.memoryBytes, "memoryBytes");
|
|
const memoryExceeded = oom || (memoryLimitBytes !== null && memoryBytes !== null && memoryBytes > memoryLimitBytes);
|
|
const signal = value.signal === null || value.signal === undefined ? null : String(value.signal);
|
|
const exitCode = value.code === null || value.code === undefined ? null : value.code;
|
|
if (exitCode !== null && (!Number.isInteger(exitCode) || exitCode < 0)) invalid("code must be a non-negative integer");
|
|
let code = SERVER_JOB_FAULT_CODES.SUCCEEDED;
|
|
let state = "SUCCEEDED";
|
|
if (cancelRequested || value.status === "CANCELLED") { code = SERVER_JOB_FAULT_CODES.CANCELLED; state = "CANCELLED"; }
|
|
else if (timedOut) { code = SERVER_JOB_FAULT_CODES.TIMEOUT; state = "FAILED"; }
|
|
else if (memoryExceeded) { code = SERVER_JOB_FAULT_CODES.OOM; state = "FAILED"; }
|
|
else if (signal) { code = SERVER_JOB_FAULT_CODES.SIGNAL; state = "FAILED"; }
|
|
else if (exitCode !== null && exitCode !== 0) { code = SERVER_JOB_FAULT_CODES.EXIT_FAILED; state = "FAILED"; }
|
|
return Object.freeze({ schemaVersion: SERVER_JOB_FAULT_SCHEMA, state, code, exitCode, signal, timedOut, memoryExceeded, publish: state === "SUCCEEDED", revisionPreserved: state !== "SUCCEEDED" });
|
|
}
|
|
|
|
export function createServerJobFaultReceipt(value) {
|
|
if (!value || typeof value !== "object") invalid("receipt input is invalid");
|
|
const baseRevision = revision(value.baseRevision, "baseRevision");
|
|
const currentRevision = revision(value.currentRevision, "currentRevision");
|
|
const classification = classifyServerJobFault(value);
|
|
if (classification.state !== "SUCCEEDED" && currentRevision !== baseRevision) {
|
|
throw new Error("SERVER_JOB_REVISION_CONFLICT: failed job cannot replace a newer project revision");
|
|
}
|
|
return Object.freeze({
|
|
schemaVersion: SERVER_JOB_FAULT_SCHEMA,
|
|
state: classification.state,
|
|
code: classification.code,
|
|
stage: "PROCESS",
|
|
exitCode: classification.exitCode,
|
|
signal: classification.signal,
|
|
timedOut: classification.timedOut,
|
|
memoryExceeded: classification.memoryExceeded,
|
|
baseRevision,
|
|
currentRevision,
|
|
committedRevision: currentRevision,
|
|
publish: classification.publish,
|
|
revisionPreserved: classification.revisionPreserved,
|
|
execution: "DISABLED",
|
|
});
|
|
}
|