Skip to content

Commit c7dd49d

Browse files
authored
chore: revert complex status endpoint logic (#167)
* Revert "chore: catch error in check service health operation (it can help debug issues like a missing permission on DynamoDB) (#160)" This reverts commit 4315886. * Revert "feat: implement service health checks for status endpoint (#156)" This reverts commit 97121ea.
1 parent 88f3d7e commit c7dd49d

File tree

3 files changed

+9
-199
lines changed

3 files changed

+9
-199
lines changed

src/operations/checkServiceHealth.ts

+5-89
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,10 @@
1-
import type { NextFunction, Request, Response } from "express";
1+
import type { Request, Response } from "express";
22
import type { ApiOperation } from "@operations/types/operation.js";
3-
import { AwsServicesConnector } from "@lib/integration/awsServicesConnector.js";
4-
import { ScanCommand } from "@aws-sdk/lib-dynamodb";
5-
import { RedisConnector } from "@lib/integration/redis/redisConnector.js";
6-
import { logMessage } from "@lib/logging/logger.js";
7-
import { ZITADEL_DOMAIN } from "@config";
8-
import { DatabaseConnectorClient } from "@lib/integration/databaseConnector.js";
9-
import axios from "axios";
103

11-
type ServiceHealthCheckResult = {
12-
service: "dynamodb" | "redis" | "postgresql" | "zitadel";
13-
isHealthy: boolean;
14-
};
15-
16-
async function main(
17-
_: Request,
18-
response: Response,
19-
next: NextFunction,
20-
): Promise<void> {
21-
try {
22-
const serviceHealthCheckResults = await Promise.all([
23-
checkDynamoDbServiceHealth(),
24-
checkRedisServiceHealth(),
25-
checkPostgreSqlServiceHealth(),
26-
checkZitadelServiceHealth(),
27-
]);
28-
29-
logMessage.info(
30-
`[service-health] ${serviceHealthCheckResults.map((r) => `${r.service} => ${r.isHealthy ? "healthy" : "unhealthy"}`).join(" | ")}`,
31-
);
32-
33-
if (serviceHealthCheckResults.some((r) => r.isHealthy === false)) {
34-
response.sendStatus(503);
35-
return;
36-
}
37-
38-
response.json({
39-
status: "healthy",
40-
});
41-
} catch (error) {
42-
next(
43-
new Error("[operation] Internal error while checking service health", {
44-
cause: error,
45-
}),
46-
);
47-
}
48-
}
49-
50-
function checkDynamoDbServiceHealth(): Promise<ServiceHealthCheckResult> {
51-
return AwsServicesConnector.getInstance()
52-
.dynamodbClient.send(
53-
new ScanCommand({
54-
TableName: "Vault",
55-
Limit: 1,
56-
}),
57-
)
58-
.then(
59-
() => true,
60-
() => false,
61-
)
62-
.then((isHealthy) => ({ service: "dynamodb", isHealthy }));
63-
}
64-
65-
function checkRedisServiceHealth(): Promise<ServiceHealthCheckResult> {
66-
return RedisConnector.getInstance()
67-
.then((redisConnector) => redisConnector.client.ping())
68-
.then(
69-
() => true,
70-
() => false,
71-
)
72-
.then((isHealthy) => ({ service: "redis", isHealthy }));
73-
}
74-
75-
function checkPostgreSqlServiceHealth(): Promise<ServiceHealthCheckResult> {
76-
return DatabaseConnectorClient.query("SELECT 1")
77-
.then(
78-
() => true,
79-
() => false,
80-
)
81-
.then((isHealthy) => ({ service: "postgresql", isHealthy }));
82-
}
83-
84-
function checkZitadelServiceHealth(): Promise<ServiceHealthCheckResult> {
85-
return axios
86-
.get(`${ZITADEL_DOMAIN}/debug/ready`, { timeout: 5000 })
87-
.then(
88-
() => true, // Zitadel answered with HTTP status 200
89-
() => false, // Zitadel answered with HTTP status 412
90-
)
91-
.then((isHealthy) => ({ service: "zitadel", isHealthy }));
4+
function main(_: Request, response: Response): void {
5+
response.json({
6+
status: "running",
7+
});
928
}
939

9410
export const checkServiceHealthOperation: ApiOperation = {
+4-107
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,23 @@
1-
import { vi, describe, it, expect, beforeEach } from "vitest";
1+
import { describe, it, expect, beforeEach } from "vitest";
22
import { getMockReq, getMockRes } from "vitest-mock-express";
33
import { checkServiceHealthOperation } from "@operations/checkServiceHealth.js";
4-
import { DatabaseConnectorClient } from "@lib/integration/databaseConnector.js";
5-
import { mockClient } from "aws-sdk-client-mock";
6-
import { DynamoDBDocumentClient, ScanCommand } from "@aws-sdk/lib-dynamodb";
7-
import { RedisConnector } from "@lib/integration/redis/redisConnector.js";
8-
import { logMessage } from "@lib/logging/logger.js";
9-
import axios from "axios";
10-
11-
const dynamoDbMock = mockClient(DynamoDBDocumentClient);
12-
13-
vi.mock("@lib/integration/redis/redisConnector");
14-
const redisConnectorMock = vi.mocked(RedisConnector);
15-
16-
// biome-ignore lint/suspicious/noExplicitAny: we need to assign the Redis client and allow mock resolved values
17-
const redisClient: any = {
18-
ping: vi.fn(),
19-
};
20-
21-
redisConnectorMock.getInstance.mockResolvedValue({ client: redisClient });
22-
23-
const logMessageSpy = vi.spyOn(logMessage, "info");
244

255
describe("checkServiceHealthOperation handler should", () => {
26-
const requestMock = getMockReq();
276
const { res: responseMock, next: nextMock, clearMockRes } = getMockRes();
287

298
beforeEach(() => {
30-
vi.clearAllMocks();
319
clearMockRes();
32-
dynamoDbMock.reset();
33-
});
34-
35-
it("respond with success if all internal services are healthy", async () => {
36-
dynamoDbMock.on(ScanCommand).resolvesOnce({ Items: [] });
37-
redisClient.ping.mockResolvedValueOnce("PONG");
38-
vi.spyOn(DatabaseConnectorClient, "query").mockResolvedValueOnce(1);
39-
vi.spyOn(axios, "get").mockResolvedValueOnce({});
40-
41-
await checkServiceHealthOperation.handler(
42-
requestMock,
43-
responseMock,
44-
nextMock,
45-
);
46-
47-
expect(logMessageSpy).toHaveBeenCalledWith(
48-
"[service-health] dynamodb => healthy | redis => healthy | postgresql => healthy | zitadel => healthy",
49-
);
50-
expect(responseMock.json).toHaveBeenCalledWith({ status: "healthy" });
5110
});
5211

53-
it("respond with error if DynamoDB service is unhealthy", async () => {
54-
dynamoDbMock.on(ScanCommand).rejectsOnce(new Error("custom error"));
55-
redisClient.ping.mockResolvedValueOnce("PONG");
56-
vi.spyOn(DatabaseConnectorClient, "query").mockResolvedValueOnce(1);
57-
vi.spyOn(axios, "get").mockResolvedValueOnce({});
12+
it("respond with running status if service is healthy", async () => {
13+
const requestMock = getMockReq();
5814

5915
await checkServiceHealthOperation.handler(
6016
requestMock,
6117
responseMock,
6218
nextMock,
6319
);
6420

65-
expect(logMessageSpy).toHaveBeenCalledWith(
66-
"[service-health] dynamodb => unhealthy | redis => healthy | postgresql => healthy | zitadel => healthy",
67-
);
68-
expect(responseMock.sendStatus).toHaveBeenCalledWith(503);
69-
});
70-
71-
it("respond with error if Redis service is unhealthy", async () => {
72-
dynamoDbMock.on(ScanCommand).resolvesOnce({ Items: [] });
73-
redisClient.ping.mockRejectedValueOnce(new Error("custom error"));
74-
vi.spyOn(DatabaseConnectorClient, "query").mockResolvedValueOnce(1);
75-
vi.spyOn(axios, "get").mockResolvedValueOnce({});
76-
77-
await checkServiceHealthOperation.handler(
78-
requestMock,
79-
responseMock,
80-
nextMock,
81-
);
82-
83-
expect(logMessageSpy).toHaveBeenCalledWith(
84-
"[service-health] dynamodb => healthy | redis => unhealthy | postgresql => healthy | zitadel => healthy",
85-
);
86-
expect(responseMock.sendStatus).toHaveBeenCalledWith(503);
87-
});
88-
89-
it("respond with error if PostgreSQL service is unhealthy", async () => {
90-
dynamoDbMock.on(ScanCommand).resolvesOnce({ Items: [] });
91-
redisClient.ping.mockResolvedValueOnce("PONG");
92-
vi.spyOn(DatabaseConnectorClient, "query").mockRejectedValueOnce(
93-
new Error("custom error"),
94-
);
95-
vi.spyOn(axios, "get").mockResolvedValueOnce({});
96-
97-
await checkServiceHealthOperation.handler(
98-
requestMock,
99-
responseMock,
100-
nextMock,
101-
);
102-
103-
expect(logMessageSpy).toHaveBeenCalledWith(
104-
"[service-health] dynamodb => healthy | redis => healthy | postgresql => unhealthy | zitadel => healthy",
105-
);
106-
expect(responseMock.sendStatus).toHaveBeenCalledWith(503);
107-
});
108-
109-
it("respond with error if Zitadel service is unhealthy", async () => {
110-
dynamoDbMock.on(ScanCommand).resolvesOnce({ Items: [] });
111-
redisClient.ping.mockResolvedValueOnce("PONG");
112-
vi.spyOn(DatabaseConnectorClient, "query").mockResolvedValueOnce(1);
113-
vi.spyOn(axios, "get").mockRejectedValueOnce(new Error("custom error"));
114-
115-
await checkServiceHealthOperation.handler(
116-
requestMock,
117-
responseMock,
118-
nextMock,
119-
);
120-
121-
expect(logMessageSpy).toHaveBeenCalledWith(
122-
"[service-health] dynamodb => healthy | redis => healthy | postgresql => healthy | zitadel => unhealthy",
123-
);
124-
expect(responseMock.sendStatus).toHaveBeenCalledWith(503);
21+
expect(responseMock.json).toHaveBeenCalledWith({ status: "running" });
12522
});
12623
});

vitest-setup.ts

-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ process.env = {
1515

1616
vi.mock("./src/lib/integration/databaseConnector", () => ({
1717
DatabaseConnectorClient: {
18-
query: vi.fn(),
1918
oneOrNone: vi.fn(),
2019
},
2120
}));
@@ -27,7 +26,6 @@ vi.mock("./src/lib/logging/auditLogs", () => ({
2726
vi.mock("axios", () => {
2827
return {
2928
default: {
30-
get: vi.fn().mockResolvedValue({}),
3129
post: vi.fn().mockResolvedValue({}),
3230
},
3331
};
@@ -49,7 +47,6 @@ vi.mock("redis", () => {
4947
connect: vi.fn().mockResolvedValue({}),
5048
quit: vi.fn(),
5149
on: vi.fn().mockReturnThis(),
52-
ping: vi.fn(),
5350
};
5451
return {
5552
createClient: vi.fn(() => client),

0 commit comments

Comments
 (0)