cleanup
This commit is contained in:
1 parent
c7689cc64a
commit
ad7d4e54c3
4 files changed
+66
-354
No files matched your search
@@ -29,7 +29,6 @@ import { NotificationMessageBuilder, INotificationMessageBuilder } from "../serv
|
||||
import axios from "axios";
|
||||
import got from "got";
|
||||
import ping from "ping";
|
||||
import https from "https";
|
||||
import Docker from "dockerode";
|
||||
import net from "net";
|
||||
import fs from "fs";
|
||||
@@ -83,6 +82,7 @@ import { HardwareProvider } from "@/service/infrastructure/network/HardwareProvi
|
||||
import { DockerProvider } from "@/service/infrastructure/network/DockerProvider.js";
|
||||
import { PortProvider } from "@/service/infrastructure/network/PortProvider.js";
|
||||
import { GameProvider } from "@/service/infrastructure/network/GameProvider.js";
|
||||
import { GrpcProvider } from "@/service/infrastructure/network/GrpcProvider.js";
|
||||
|
||||
export type InitializedServices = {
|
||||
settingsService: any;
|
||||
@@ -161,29 +161,19 @@ export const initializeServices = async ({
|
||||
const dockerProvider = new DockerProvider(logger, Docker);
|
||||
const portProvider = new PortProvider(net);
|
||||
const gameProvider = new GameProvider(logger, GameDig);
|
||||
const grpcProvider = new GrpcProvider(grpc, protoLoader);
|
||||
|
||||
const networkService = new NetworkService(
|
||||
axios,
|
||||
got,
|
||||
https,
|
||||
jmespath,
|
||||
GameDig as unknown as {
|
||||
query: (options: { type: string; host: string; port?: number }) => Promise<{ ping?: number } & { [key: string]: unknown }>;
|
||||
},
|
||||
ping,
|
||||
logger,
|
||||
Docker,
|
||||
net,
|
||||
settingsService,
|
||||
grpc,
|
||||
protoLoader,
|
||||
pingProvider,
|
||||
httpProvider,
|
||||
pageSpeedProvider,
|
||||
hardwareProvider,
|
||||
dockerProvider,
|
||||
portProvider,
|
||||
gameProvider
|
||||
gameProvider,
|
||||
grpcProvider
|
||||
);
|
||||
const emailService = new EmailService(settingsService, fs, path, compile, mjml2html, nodemailer, logger);
|
||||
|
||||
|
||||
@@ -2,29 +2,21 @@ import { IStatusProvider } from "@/service/infrastructure/network/IStatusProvide
|
||||
import { GrpcStatusPayload, MonitorStatusResponse } from "@/types/network.js";
|
||||
import { Monitor, MonitorType } from "@/types/monitor.js";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
import { NETWORK_ERROR, timeRequest } from "@/service/infrastructure/network/utils.js";
|
||||
import { ILogger } from "@/utils/logger.js";
|
||||
import { timeRequest } from "@/service/infrastructure/network/utils.js";
|
||||
import * as grpc from "@grpc/grpc-js";
|
||||
import * as protoLoader from "@grpc/proto-loader";
|
||||
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { Network } from "inspector/promises";
|
||||
|
||||
type GrpcType = typeof grpc;
|
||||
type ProtoLoaderType = typeof protoLoader;
|
||||
|
||||
const SERVICE_NAME = "GrpcProvider";
|
||||
|
||||
export interface GrpcError extends Error {
|
||||
code: number;
|
||||
details?: string;
|
||||
}
|
||||
|
||||
export class GrpcProvider implements IStatusProvider<GrpcStatusPayload> {
|
||||
readonly type = "grpc";
|
||||
constructor(
|
||||
private logger: ILogger,
|
||||
private grpc: GrpcType,
|
||||
private protoLoader: ProtoLoaderType
|
||||
) {}
|
||||
@@ -33,10 +25,6 @@ export class GrpcProvider implements IStatusProvider<GrpcStatusPayload> {
|
||||
return type === "grpc";
|
||||
}
|
||||
|
||||
private isGrpcError(error: unknown): error is GrpcError {
|
||||
return error instanceof Error && "code" in error && typeof (error as Record<string, unknown>).code === "number";
|
||||
}
|
||||
|
||||
private getGrpcStatusName(code: number): string {
|
||||
const statusNames: Record<number, string> = {
|
||||
0: "OK",
|
||||
@@ -61,15 +49,20 @@ export class GrpcProvider implements IStatusProvider<GrpcStatusPayload> {
|
||||
}
|
||||
|
||||
async handle(monitor: Monitor): Promise<MonitorStatusResponse<GrpcStatusPayload>> {
|
||||
const { id, teamId, type, url, port, ignoreTlsErrors } = monitor;
|
||||
const grpcServiceName = monitor.grpcServiceName || "";
|
||||
const host = url?.replace(/^https?:\/\//, "").split(/[/?#:]/)[0];
|
||||
|
||||
try {
|
||||
if (!host || !port) {
|
||||
throw new Error("Valid host and port are required");
|
||||
const { id, teamId, type, url, port, ignoreTlsErrors } = monitor;
|
||||
const grpcServiceName = monitor.grpcServiceName || "";
|
||||
|
||||
if (!url) {
|
||||
throw new AppError({ message: "Monitor host is required", service: SERVICE_NAME, method: "handle" });
|
||||
}
|
||||
if (!port) {
|
||||
throw new AppError({ message: "Monitor port is required", service: SERVICE_NAME, method: "handle" });
|
||||
}
|
||||
|
||||
const host = url?.replace(/^https?:\/\//, "").split(/[/?#:]/)[0];
|
||||
const target = `${host}:${port}`;
|
||||
|
||||
const currentFilePath = fileURLToPath(import.meta.url);
|
||||
const protoPath = path.join(path.dirname(currentFilePath), "protos", "health.proto");
|
||||
const packageDefinition = this.protoLoader.loadSync(protoPath, {
|
||||
@@ -79,8 +72,23 @@ export class GrpcProvider implements IStatusProvider<GrpcStatusPayload> {
|
||||
defaults: true,
|
||||
oneofs: true,
|
||||
});
|
||||
const grpcObject = this.grpc.loadPackageDefinition(packageDefinition) as any;
|
||||
const HealthClient = grpcObject.grpc.health.v1.Health;
|
||||
const grpcObject = this.grpc.loadPackageDefinition(packageDefinition) as unknown as {
|
||||
grpc: {
|
||||
health: {
|
||||
v1: {
|
||||
Health: new (
|
||||
target: string,
|
||||
credentials: unknown
|
||||
) => {
|
||||
Check: (request: { service: string }, options: { deadline: Date }, callback: (err: unknown, response: unknown) => void) => void;
|
||||
close: () => void;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
const healthService = grpcObject.grpc.health.v1.Health;
|
||||
|
||||
let credentials;
|
||||
if (ignoreTlsErrors) {
|
||||
credentials = this.grpc.credentials.createSsl(null, null, null, {
|
||||
@@ -89,8 +97,12 @@ export class GrpcProvider implements IStatusProvider<GrpcStatusPayload> {
|
||||
} else {
|
||||
credentials = this.grpc.credentials.createInsecure();
|
||||
}
|
||||
const client = new HealthClient(target, credentials);
|
||||
const deadline = new Date(Date.now() + 10000); // 10s timeout
|
||||
|
||||
const client = new healthService(target, credentials);
|
||||
|
||||
const TIMEOUT_MS = 10000;
|
||||
const deadline = new Date(Date.now() + TIMEOUT_MS);
|
||||
|
||||
const { response, responseTime, error } = await timeRequest<GrpcStatusPayload>(() => {
|
||||
return new Promise<GrpcStatusPayload>((resolve, reject) => {
|
||||
client.Check({ service: grpcServiceName }, { deadline }, (err: unknown, response: unknown) => {
|
||||
@@ -128,51 +140,32 @@ export class GrpcProvider implements IStatusProvider<GrpcStatusPayload> {
|
||||
});
|
||||
|
||||
if (error) {
|
||||
let grpcCode = -1;
|
||||
let message = error instanceof Error ? error.message : "gRPC health check failed";
|
||||
|
||||
if (this.isGrpcError(error)) {
|
||||
grpcCode = error.code;
|
||||
message = error.details || error.message;
|
||||
}
|
||||
|
||||
const grpcError = error as AppError & { grpcPayload?: GrpcStatusPayload; grpcCode?: number };
|
||||
const payload = grpcError.grpcPayload;
|
||||
return {
|
||||
monitorId: id,
|
||||
teamId: teamId,
|
||||
type: type,
|
||||
status: false,
|
||||
code: 500,
|
||||
message: message,
|
||||
code: grpcError.grpcCode ?? 5000,
|
||||
message: grpcError.message ?? "gRPC health check failed",
|
||||
responseTime,
|
||||
payload: {
|
||||
grpcStatusCode: grpcCode,
|
||||
grpcStatusName: this.getGrpcStatusName(grpcCode),
|
||||
serviceName: grpcServiceName,
|
||||
servingStatus: "UNKNOWN",
|
||||
},
|
||||
payload: payload ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
throw new Error("No response received from gRPC health check");
|
||||
}
|
||||
|
||||
const isServing = response.servingStatus === "SERVING";
|
||||
const grpcPayload = response as GrpcStatusPayload;
|
||||
const isServing = grpcPayload.servingStatus === "SERVING";
|
||||
|
||||
return {
|
||||
monitorId: id,
|
||||
teamId: teamId,
|
||||
type: type,
|
||||
status: isServing,
|
||||
code: isServing ? 200 : NETWORK_ERROR,
|
||||
message: isServing ? "gRPC health check successful" : "gRPC health check failed",
|
||||
code: isServing ? 200 : 5000,
|
||||
message: isServing ? `gRPC service healthy (${grpcPayload.servingStatus})` : `gRPC service unhealthy (${grpcPayload.servingStatus})`,
|
||||
responseTime,
|
||||
payload: {
|
||||
grpcStatusCode: isServing ? 200 : NETWORK_ERROR,
|
||||
grpcStatusName: response.grpcStatusName,
|
||||
serviceName: response.serviceName,
|
||||
servingStatus: response.servingStatus || "UNKNOWN",
|
||||
},
|
||||
payload: grpcPayload,
|
||||
};
|
||||
} catch (err: unknown) {
|
||||
const originalMessage = err instanceof Error ? err.message : String(err);
|
||||
|
||||
@@ -6,6 +6,7 @@ import { MonitorStatusResponse } from "@/types/network.js";
|
||||
import { Agent as HttpsAgent } from "https";
|
||||
import { Monitor, MonitorType } from "@/types/monitor.js";
|
||||
import { NETWORK_ERROR } from "@/service/infrastructure/network/utils.js";
|
||||
import CacheableLookup from "cacheable-lookup";
|
||||
|
||||
export class HttpProvider implements IStatusProvider<HttpStatusPayload> {
|
||||
readonly type = "http";
|
||||
@@ -13,7 +14,16 @@ export class HttpProvider implements IStatusProvider<HttpStatusPayload> {
|
||||
constructor(
|
||||
private got: Got,
|
||||
private advancedMatcher: AdvancedMatcher
|
||||
) {}
|
||||
) {
|
||||
const cacheable = new CacheableLookup();
|
||||
this.got = got.extend({
|
||||
dnsCache: cacheable,
|
||||
timeout: {
|
||||
request: 30000,
|
||||
},
|
||||
retry: { limit: 1 },
|
||||
});
|
||||
}
|
||||
|
||||
supports(type: MonitorType) {
|
||||
return type === "http";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { HTTPError, RequestError } from "got";
|
||||
import type { Got, Response } from "got";
|
||||
import type { Got } from "got";
|
||||
import type {
|
||||
Monitor,
|
||||
MonitorStatusResponse,
|
||||
@@ -14,28 +13,12 @@ import type {
|
||||
} from "@/types/index.js";
|
||||
import type { AxiosStatic } from "axios";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { MonitorStatusResponseOverrides } from "@/types/index.js";
|
||||
|
||||
import CacheableLookup from "cacheable-lookup";
|
||||
import { ISettingsService } from "../system/settingsService.js";
|
||||
import { ILogger } from "@/utils/logger.js";
|
||||
import { IStatusProvider } from "./network/IStatusProvider.js";
|
||||
const SERVICE_NAME = "NetworkService";
|
||||
|
||||
interface BuildStatusResponseArgs<T> {
|
||||
monitor: Monitor;
|
||||
response?: Response<T> | null;
|
||||
error?: Error | RequestError | HTTPError | null;
|
||||
payload?: T | null;
|
||||
jsonPath?: string;
|
||||
matchMethod?: MonitorStatusResponse["matchMethod"];
|
||||
expectedValue?: string;
|
||||
extracted?: unknown;
|
||||
overrides?: MonitorStatusResponseOverrides<T>;
|
||||
}
|
||||
|
||||
export interface INetworkService {
|
||||
readonly serviceName: string;
|
||||
requestStatus(
|
||||
@@ -82,19 +65,7 @@ class NetworkService implements INetworkService {
|
||||
private PING_ERROR: number;
|
||||
|
||||
private axios: AxiosStatic;
|
||||
private got: Got;
|
||||
private https: typeof import("https");
|
||||
private jmespath: { search: (data: unknown, expression: string) => unknown };
|
||||
private GameDig: { query: (options: { type: string; host: string; port?: number }) => Promise<{ ping?: number } & { [key: string]: unknown }> };
|
||||
private ping: typeof import("ping");
|
||||
private logger: ILogger;
|
||||
private Docker: typeof import("dockerode");
|
||||
private net: typeof import("net");
|
||||
private settingsService: ISettingsService;
|
||||
private grpc: typeof import("@grpc/grpc-js");
|
||||
private protoLoader: typeof import("@grpc/proto-loader");
|
||||
|
||||
// New providers
|
||||
private pingProvider;
|
||||
private httpProvider;
|
||||
private pageSpeedProvider;
|
||||
@@ -102,83 +73,19 @@ class NetworkService implements INetworkService {
|
||||
private dockerProvider;
|
||||
private portProvider;
|
||||
private gameProvider;
|
||||
|
||||
private buildStatusResponse = <T>({
|
||||
monitor,
|
||||
response,
|
||||
error,
|
||||
payload,
|
||||
jsonPath,
|
||||
matchMethod,
|
||||
expectedValue,
|
||||
extracted,
|
||||
overrides,
|
||||
}: BuildStatusResponseArgs<T>): MonitorStatusResponse<T> => {
|
||||
if (error) {
|
||||
const statusResponse: MonitorStatusResponse<T> = {
|
||||
monitorId: monitor.id,
|
||||
teamId: monitor.teamId,
|
||||
type: monitor.type,
|
||||
status: false,
|
||||
code: this.NETWORK_ERROR,
|
||||
message: error.message ?? "Network error",
|
||||
responseTime: 0,
|
||||
timings: undefined,
|
||||
jsonPath,
|
||||
matchMethod,
|
||||
expectedValue,
|
||||
extracted,
|
||||
payload,
|
||||
};
|
||||
if (error instanceof HTTPError || error instanceof RequestError) {
|
||||
statusResponse.code = error?.response?.statusCode ?? this.NETWORK_ERROR;
|
||||
statusResponse.message = error.message;
|
||||
statusResponse.responseTime = error.timings?.phases?.total ?? 0;
|
||||
statusResponse.timings = error.timings;
|
||||
}
|
||||
return { ...statusResponse, ...(overrides ?? {}) } as MonitorStatusResponse<T>;
|
||||
}
|
||||
|
||||
return {
|
||||
monitorId: monitor.id,
|
||||
teamId: monitor.teamId,
|
||||
type: monitor.type,
|
||||
status: response?.ok ?? false,
|
||||
code: response?.statusCode ?? this.NETWORK_ERROR,
|
||||
message: response?.statusMessage ?? "",
|
||||
responseTime: response?.timings?.phases?.total ?? 0,
|
||||
timings: response?.timings,
|
||||
payload: payload ?? response?.body,
|
||||
jsonPath,
|
||||
matchMethod,
|
||||
expectedValue,
|
||||
extracted,
|
||||
...(overrides ?? {}),
|
||||
} as MonitorStatusResponse<T>;
|
||||
};
|
||||
private grpcProvider;
|
||||
|
||||
constructor(
|
||||
axios: AxiosStatic,
|
||||
got: Got,
|
||||
https: typeof import("https"),
|
||||
jmespath: { search: (data: unknown, expression: string) => unknown },
|
||||
GameDig: { query: (options: { type: string; host: string; port?: number }) => Promise<{ ping?: number } & { [key: string]: unknown }> },
|
||||
ping: typeof import("ping"),
|
||||
logger: ILogger,
|
||||
Docker: typeof import("dockerode"),
|
||||
net: typeof import("net"),
|
||||
settingsService: ISettingsService,
|
||||
grpc: typeof import("@grpc/grpc-js"),
|
||||
protoLoader: typeof import("@grpc/proto-loader"),
|
||||
|
||||
// New providers
|
||||
pingProvider: IStatusProvider<PingStatusPayload>,
|
||||
httpProvider: IStatusProvider<HttpStatusPayload>,
|
||||
pagespeedProvider: IStatusProvider<PageSpeedStatusPayload>,
|
||||
hardwareProvider: IStatusProvider<HardwareStatusPayload>,
|
||||
dockerProvider: IStatusProvider<DockerStatusPayload>,
|
||||
portProvider: IStatusProvider<PortStatusPayload>,
|
||||
gameProvider: IStatusProvider<GameStatusPayload>
|
||||
gameProvider: IStatusProvider<GameStatusPayload>,
|
||||
grpcProvider: IStatusProvider<GrpcStatusPayload>
|
||||
) {
|
||||
this.TYPE_PING = "ping";
|
||||
this.TYPE_HTTP = "http";
|
||||
@@ -192,18 +99,8 @@ class NetworkService implements INetworkService {
|
||||
this.NETWORK_ERROR = 5000;
|
||||
this.PING_ERROR = 5001;
|
||||
this.axios = axios;
|
||||
this.https = https;
|
||||
this.jmespath = jmespath;
|
||||
this.GameDig = GameDig;
|
||||
this.ping = ping;
|
||||
this.logger = logger;
|
||||
this.Docker = Docker;
|
||||
this.net = net;
|
||||
this.settingsService = settingsService;
|
||||
this.grpc = grpc;
|
||||
this.protoLoader = protoLoader;
|
||||
|
||||
// New providers
|
||||
this.pingProvider = pingProvider;
|
||||
this.httpProvider = httpProvider;
|
||||
this.pageSpeedProvider = pagespeedProvider;
|
||||
@@ -211,34 +108,13 @@ class NetworkService implements INetworkService {
|
||||
this.dockerProvider = dockerProvider;
|
||||
this.portProvider = portProvider;
|
||||
this.gameProvider = gameProvider;
|
||||
const cacheable = new CacheableLookup();
|
||||
|
||||
this.got = got.extend({
|
||||
dnsCache: cacheable,
|
||||
timeout: {
|
||||
request: 30000,
|
||||
},
|
||||
retry: { limit: 1 },
|
||||
});
|
||||
this.grpcProvider = grpcProvider;
|
||||
}
|
||||
|
||||
get serviceName(): string {
|
||||
return NetworkService.SERVICE_NAME;
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
private async timeRequest<T>(operation: () => Promise<T>): Promise<{ response: T | null; responseTime: number; error: unknown }> {
|
||||
const start = process.hrtime.bigint();
|
||||
try {
|
||||
const response = await operation();
|
||||
const elapsedMs = Math.round(Number(process.hrtime.bigint() - start) / 1_000_000);
|
||||
return { response, responseTime: elapsedMs, error: null };
|
||||
} catch (error) {
|
||||
const elapsedMs = Math.round(Number(process.hrtime.bigint() - start) / 1_000_000);
|
||||
return { response: null, responseTime: elapsedMs, error };
|
||||
}
|
||||
}
|
||||
|
||||
// Main entry point
|
||||
async requestStatus(
|
||||
monitor: Monitor
|
||||
@@ -271,169 +147,12 @@ class NetworkService implements INetworkService {
|
||||
case this.TYPE_GAME:
|
||||
return await this.gameProvider.handle(monitor);
|
||||
case this.TYPE_GRPC:
|
||||
return await this.requestGrpc(monitor);
|
||||
return await this.grpcProvider.handle(monitor);
|
||||
default:
|
||||
return this.handleUnsupportedType(type);
|
||||
}
|
||||
}
|
||||
|
||||
private async requestGrpc(monitor: Monitor): Promise<MonitorStatusResponse<GrpcStatusPayload>> {
|
||||
try {
|
||||
const { url, port, ignoreTlsErrors } = monitor;
|
||||
const grpcServiceName = monitor.grpcServiceName || "";
|
||||
|
||||
if (!url) {
|
||||
throw new AppError({ message: "Monitor host is required", service: this.SERVICE_NAME, method: "requestGrpc" });
|
||||
}
|
||||
if (!port) {
|
||||
throw new AppError({ message: "Monitor port is required", service: this.SERVICE_NAME, method: "requestGrpc" });
|
||||
}
|
||||
|
||||
const target = `${url}:${port}`;
|
||||
|
||||
const currentFilePath = fileURLToPath(import.meta.url);
|
||||
const protoPath = path.join(path.dirname(currentFilePath), "protos", "health.proto");
|
||||
|
||||
const packageDefinition = this.protoLoader.loadSync(protoPath, {
|
||||
keepCase: true,
|
||||
longs: String,
|
||||
enums: String,
|
||||
defaults: true,
|
||||
oneofs: true,
|
||||
});
|
||||
const grpcObject = this.grpc.loadPackageDefinition(packageDefinition) as unknown as {
|
||||
grpc: {
|
||||
health: {
|
||||
v1: {
|
||||
Health: new (
|
||||
target: string,
|
||||
credentials: unknown
|
||||
) => {
|
||||
Check: (request: { service: string }, options: { deadline: Date }, callback: (err: unknown, response: unknown) => void) => void;
|
||||
close: () => void;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
const healthService = grpcObject.grpc.health.v1.Health;
|
||||
|
||||
let credentials;
|
||||
if (ignoreTlsErrors) {
|
||||
credentials = this.grpc.credentials.createSsl(null, null, null, {
|
||||
checkServerIdentity: () => undefined,
|
||||
});
|
||||
} else {
|
||||
credentials = this.grpc.credentials.createInsecure();
|
||||
}
|
||||
|
||||
const client = new healthService(target, credentials);
|
||||
|
||||
const TIMEOUT_MS = 10000;
|
||||
const deadline = new Date(Date.now() + TIMEOUT_MS);
|
||||
|
||||
const grpcResponse = this.buildStatusResponse<GrpcStatusPayload>({
|
||||
monitor,
|
||||
overrides: {
|
||||
status: false,
|
||||
code: this.NETWORK_ERROR,
|
||||
message: "gRPC health check not executed",
|
||||
},
|
||||
});
|
||||
|
||||
const { response, responseTime, error } = await this.timeRequest<GrpcStatusPayload>(() => {
|
||||
return new Promise<GrpcStatusPayload>((resolve, reject) => {
|
||||
client.Check({ service: grpcServiceName }, { deadline }, (err: unknown, response: unknown) => {
|
||||
client.close();
|
||||
|
||||
if (err) {
|
||||
const grpcErr = err as { code?: number; details?: string; message?: string };
|
||||
const payload: GrpcStatusPayload = {
|
||||
grpcStatusCode: grpcErr.code ?? -1,
|
||||
grpcStatusName: this.getGrpcStatusName(grpcErr.code ?? -1),
|
||||
serviceName: grpcServiceName,
|
||||
servingStatus: "UNKNOWN",
|
||||
};
|
||||
const grpcError = new AppError({
|
||||
message: grpcErr.details || grpcErr.message || "gRPC error",
|
||||
service: this.SERVICE_NAME,
|
||||
method: "requestGrpc",
|
||||
}) as AppError & { grpcPayload?: GrpcStatusPayload; grpcCode?: number };
|
||||
grpcError.grpcPayload = payload;
|
||||
grpcError.grpcCode = grpcErr.code;
|
||||
reject(grpcError);
|
||||
return;
|
||||
}
|
||||
|
||||
const resp = response as { status?: string } | undefined;
|
||||
const servingStatus = resp?.status ?? "UNKNOWN";
|
||||
resolve({
|
||||
grpcStatusCode: 0,
|
||||
grpcStatusName: "OK",
|
||||
serviceName: grpcServiceName,
|
||||
servingStatus,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (error) {
|
||||
const grpcError = error as AppError & { grpcPayload?: GrpcStatusPayload; grpcCode?: number };
|
||||
const payload = grpcError.grpcPayload;
|
||||
grpcResponse.status = false;
|
||||
grpcResponse.code = grpcError.grpcCode ?? this.NETWORK_ERROR;
|
||||
grpcResponse.message = grpcError.message ?? "gRPC health check failed";
|
||||
grpcResponse.responseTime = responseTime;
|
||||
grpcResponse.payload = payload ?? null;
|
||||
return grpcResponse;
|
||||
}
|
||||
|
||||
const grpcPayload = response as GrpcStatusPayload;
|
||||
const isServing = grpcPayload.servingStatus === "SERVING";
|
||||
|
||||
grpcResponse.status = isServing;
|
||||
grpcResponse.code = isServing ? 200 : this.NETWORK_ERROR;
|
||||
grpcResponse.message = isServing
|
||||
? `gRPC service healthy (${grpcPayload.servingStatus})`
|
||||
: `gRPC service unhealthy (${grpcPayload.servingStatus})`;
|
||||
grpcResponse.responseTime = responseTime;
|
||||
grpcResponse.payload = grpcPayload;
|
||||
|
||||
return grpcResponse;
|
||||
} catch (err: unknown) {
|
||||
const originalMessage = err instanceof Error ? err.message : String(err);
|
||||
throw new AppError({
|
||||
message: originalMessage || "Error performing gRPC health check",
|
||||
service: this.SERVICE_NAME,
|
||||
method: "requestGrpc",
|
||||
details: { url: monitor.url, port: monitor.port, grpcServiceName: monitor.grpcServiceName },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getGrpcStatusName(code: number): string {
|
||||
const statusNames: Record<number, string> = {
|
||||
0: "OK",
|
||||
1: "CANCELLED",
|
||||
2: "UNKNOWN",
|
||||
3: "INVALID_ARGUMENT",
|
||||
4: "DEADLINE_EXCEEDED",
|
||||
5: "NOT_FOUND",
|
||||
6: "ALREADY_EXISTS",
|
||||
7: "PERMISSION_DENIED",
|
||||
8: "RESOURCE_EXHAUSTED",
|
||||
9: "FAILED_PRECONDITION",
|
||||
10: "ABORTED",
|
||||
11: "OUT_OF_RANGE",
|
||||
12: "UNIMPLEMENTED",
|
||||
13: "INTERNAL",
|
||||
14: "UNAVAILABLE",
|
||||
15: "DATA_LOSS",
|
||||
16: "UNAUTHENTICATED",
|
||||
};
|
||||
return statusNames[code] || "UNKNOWN";
|
||||
}
|
||||
|
||||
private async handleUnsupportedType(type: string): Promise<MonitorStatusResponse> {
|
||||
return {
|
||||
monitorId: "unknown",
|
||||
|
||||
Reference in new issue
Block a user