feat: add health check API and handle app configuration warnings
- Removed the old index.html file from the frontend build. - Integrated a health check query in App component to verify app configuration. - Display a warning alert if the app is not configured with AZURE_SUBSCRIPTION_ID. - Updated API module to include health check endpoint.
This commit is contained in:
@@ -42,27 +42,32 @@ const makeApp = () => {
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
if (!subscriptionId) {
|
||||
app.get("/api/health", (_req, res) => {
|
||||
const azure = subscriptionId ? new AzureImageService(subscriptionId) : null;
|
||||
const templates = new TemplateService();
|
||||
|
||||
app.get("/api/health", (_req, res) => {
|
||||
if (!subscriptionId) {
|
||||
res.status(500).json({
|
||||
status: "error",
|
||||
message: "Missing AZURE_SUBSCRIPTION_ID"
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return { app, port };
|
||||
}
|
||||
|
||||
const azure = new AzureImageService(subscriptionId);
|
||||
const templates = new TemplateService();
|
||||
|
||||
app.get("/api/health", (_req, res) => {
|
||||
res.json({ status: "ok" });
|
||||
});
|
||||
|
||||
const requireAzure = (): AzureImageService => {
|
||||
if (!azure) {
|
||||
throw new Error("Missing AZURE_SUBSCRIPTION_ID");
|
||||
}
|
||||
|
||||
return azure;
|
||||
};
|
||||
|
||||
app.get("/api/locations", async (_req, res, next) => {
|
||||
try {
|
||||
res.json(await azure.getLocations());
|
||||
res.json(await requireAzure().getLocations());
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
@@ -71,7 +76,7 @@ const makeApp = () => {
|
||||
app.get("/api/publishers", async (req, res, next) => {
|
||||
try {
|
||||
const { location } = queryLocation.parse(req.query);
|
||||
res.json(await azure.getPublishers(location));
|
||||
res.json(await requireAzure().getPublishers(location));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
@@ -80,7 +85,7 @@ const makeApp = () => {
|
||||
app.get("/api/offers", async (req, res, next) => {
|
||||
try {
|
||||
const { location, publisher } = queryOffer.parse(req.query);
|
||||
res.json(await azure.getOffers(location, publisher));
|
||||
res.json(await requireAzure().getOffers(location, publisher));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
@@ -89,7 +94,7 @@ const makeApp = () => {
|
||||
app.get("/api/skus", async (req, res, next) => {
|
||||
try {
|
||||
const { location, publisher, offer } = querySku.parse(req.query);
|
||||
res.json(await azure.getSkus(location, publisher, offer));
|
||||
res.json(await requireAzure().getSkus(location, publisher, offer));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
@@ -98,7 +103,7 @@ const makeApp = () => {
|
||||
app.get("/api/versions", async (req, res, next) => {
|
||||
try {
|
||||
const { location, publisher, offer, sku } = queryVersion.parse(req.query);
|
||||
res.json(await azure.getVersions(location, publisher, offer, sku));
|
||||
res.json(await requireAzure().getVersions(location, publisher, offer, sku));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
@@ -121,7 +126,7 @@ const makeApp = () => {
|
||||
app.get("/api/sku-export", async (req, res, next) => {
|
||||
try {
|
||||
const { location, publisher, offer } = querySku.parse(req.query);
|
||||
const skus = await azure.getSkus(location, publisher, offer);
|
||||
const skus = await requireAzure().getSkus(location, publisher, offer);
|
||||
res.json({ rendered: templates.buildSkuExport(skus) });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -151,10 +156,40 @@ const makeApp = () => {
|
||||
|
||||
if (require.main === module) {
|
||||
const { app, port } = makeApp();
|
||||
app.listen(port, () => {
|
||||
const server = app.listen(port, () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`azure-image-chooser listening on ${port}`);
|
||||
});
|
||||
|
||||
let shuttingDown = false;
|
||||
const shutdown = (signal: NodeJS.Signals) => {
|
||||
if (shuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
shuttingDown = true;
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`received ${signal}, shutting down`);
|
||||
server.close((error) => {
|
||||
if (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("graceful shutdown failed", error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// Force-exit if connections do not close in time.
|
||||
setTimeout(() => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("shutdown timeout reached, forcing exit");
|
||||
process.exit(1);
|
||||
}, 10_000).unref();
|
||||
};
|
||||
|
||||
process.on("SIGTERM", shutdown);
|
||||
process.on("SIGINT", shutdown);
|
||||
}
|
||||
|
||||
export { makeApp };
|
||||
|
||||
Reference in New Issue
Block a user