chore: initial project import
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
This commit is contained in:
123
scripts/ops-healthcheck.mjs
Normal file
123
scripts/ops-healthcheck.mjs
Normal file
@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const BASE_URL = resolveBaseUrl();
|
||||
const token = process.env.CAMPAIGN_RETRY_JOB_TOKEN?.trim();
|
||||
const healthToken = process.env.HEALTHCHECK_TOKEN?.trim();
|
||||
|
||||
if (!BASE_URL) {
|
||||
console.error("Missing APP_URL / NEXT_PUBLIC_APP_URL / OPS_BASE_URL");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function resolveBaseUrl() {
|
||||
return [
|
||||
process.env.OPS_BASE_URL,
|
||||
process.env.APP_URL,
|
||||
process.env.NEXT_PUBLIC_APP_URL
|
||||
].map((value) => value?.trim()).find(Boolean);
|
||||
}
|
||||
|
||||
function buildUrl(path) {
|
||||
return `${BASE_URL.replace(/\/+$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
||||
}
|
||||
|
||||
async function requestJson(url, options = {}) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 12_000);
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
...options.headers
|
||||
},
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
const text = await response.text();
|
||||
clearTimeout(timeout);
|
||||
|
||||
let parsed = null;
|
||||
try {
|
||||
parsed = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
parsed = text;
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
ok: response.ok,
|
||||
data: parsed,
|
||||
raw: response.ok ? null : text
|
||||
};
|
||||
} catch (error) {
|
||||
clearTimeout(timeout);
|
||||
return {
|
||||
status: 0,
|
||||
ok: false,
|
||||
data: null,
|
||||
raw: error instanceof Error ? error.message : String(error)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function appendToken(url, tokenValue) {
|
||||
if (!tokenValue) {
|
||||
return url;
|
||||
}
|
||||
|
||||
const parsed = new URL(url);
|
||||
if (!parsed.searchParams.get("token")) {
|
||||
parsed.searchParams.set("token", tokenValue);
|
||||
}
|
||||
return parsed.toString();
|
||||
}
|
||||
|
||||
function passFail(ok) {
|
||||
return ok ? "PASS" : "FAIL";
|
||||
}
|
||||
|
||||
const results = [];
|
||||
const checks = [
|
||||
{
|
||||
name: "Application root",
|
||||
url: buildUrl("/"),
|
||||
headers: {}
|
||||
},
|
||||
{
|
||||
name: "Health endpoint",
|
||||
url: buildUrl("/api/health"),
|
||||
headers: healthToken
|
||||
? {
|
||||
Authorization: `Bearer ${healthToken}`
|
||||
}
|
||||
: {}
|
||||
},
|
||||
{
|
||||
name: "Campaign retry job state",
|
||||
url: appendToken(buildUrl("/api/jobs/campaign-retry"), token),
|
||||
headers: token
|
||||
? {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
: {}
|
||||
}
|
||||
];
|
||||
|
||||
for (const check of checks) {
|
||||
const result = await requestJson(check.url, { headers: check.headers });
|
||||
results.push({ ...check, result });
|
||||
console.log(`[${passFail(result.ok)}] ${check.name}: ${result.status}`);
|
||||
}
|
||||
|
||||
const failedChecks = results.filter((item) => !item.result.ok);
|
||||
if (failedChecks.length > 0) {
|
||||
console.error("Some health checks failed");
|
||||
for (const item of failedChecks) {
|
||||
console.error(`- ${item.name}: ${item.result.raw || JSON.stringify(item.result.data)}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("All checks passed.");
|
||||
Reference in New Issue
Block a user