feat(msg): 完整实现 msg 消息服务

包含 channels/preferences/templates/grpc/kafka/outbox/push/redis 等完整实现
This commit is contained in:
SpecialX
2026-07-10 19:09:52 +08:00
parent 21530dc7f6
commit 7b7abbb309
51 changed files with 5204 additions and 371 deletions

View File

@@ -4,25 +4,234 @@ const registry = new promClient.Registry();
// 修复:在本地 registry 上设置默认标签(原代码误用全局 register
registry.setDefaultLabels({ service: "msg" });
// ============================================================
// HTTP 指标02-architecture-design.md §6.4
// ============================================================
registry.registerMetric(
new promClient.Counter({
name: "msg_requests_total",
help: "Total number of msg requests",
labelNames: ["method", "endpoint", "status"],
name: "msg_http_requests_total",
help: "Total number of msg HTTP requests",
labelNames: ["method", "route", "status_code"],
}),
);
registry.registerMetric(
new promClient.Histogram({
name: "msg_request_duration_seconds",
help: "Msg request duration in seconds",
labelNames: ["method", "endpoint"],
name: "msg_http_request_duration_seconds",
help: "Msg HTTP request duration in seconds",
labelNames: ["method", "route"],
buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5],
}),
);
// ============================================================
// gRPC 指标
// ============================================================
registry.registerMetric(
new promClient.Counter({
name: "msg_grpc_requests_total",
help: "Total number of msg gRPC requests",
labelNames: ["rpc_method", "status"],
}),
);
// ============================================================
// 业务指标:通知发送
// ============================================================
registry.registerMetric(
new promClient.Counter({
name: "msg_notification_sent_total",
help: "Total number of notifications sent",
labelNames: ["type", "channel", "status"],
}),
);
registry.registerMetric(
new promClient.Histogram({
name: "msg_notification_send_duration_seconds",
help: "Notification send duration in seconds",
labelNames: ["type", "channel"],
buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5],
}),
);
registry.registerMetric(
new promClient.Counter({
name: "msg_notification_failed_total",
help: "Total number of notification send failures",
labelNames: ["type", "channel", "error_code"],
}),
);
// ============================================================
// 业务指标:通知已读
// ============================================================
registry.registerMetric(
new promClient.Counter({
name: "msg_notification_read_total",
help: "Total number of notifications marked as read",
labelNames: ["type"],
}),
);
// ============================================================
// 业务指标:渠道分发
// ============================================================
registry.registerMetric(
new promClient.Histogram({
name: "msg_channel_dispatch_duration_seconds",
help: "Channel dispatch duration in seconds",
labelNames: ["channel"],
buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5],
}),
);
// ============================================================
// Kafka 消费指标
// ============================================================
registry.registerMetric(
new promClient.Gauge({
name: "msg_kafka_consumer_lag",
help: "Kafka consumer lag (offset difference)",
labelNames: ["topic"],
}),
);
registry.registerMetric(
new promClient.Counter({
name: "msg_kafka_consumer_processed_total",
help: "Total number of Kafka messages processed",
labelNames: ["topic", "status"],
}),
);
// ============================================================
// 幂等去重指标
// ============================================================
registry.registerMetric(
new promClient.Counter({
name: "msg_idempotent_duplicate_total",
help: "Total number of idempotent duplicate hits",
labelNames: ["topic"],
}),
);
// ============================================================
// Outbox 指标
// ============================================================
registry.registerMetric(
new promClient.Gauge({
name: "msg_outbox_pending_count",
help: "Number of pending outbox events",
}),
);
// ============================================================
// Push Gateway 指标
// ============================================================
registry.registerMetric(
new promClient.Counter({
name: "msg_push_gateway_call_total",
help: "Total number of Push Gateway calls",
labelNames: ["status"],
}),
);
registry.registerMetric(
new promClient.Histogram({
name: "msg_push_gateway_call_duration_seconds",
help: "Push Gateway call duration in seconds",
buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5],
}),
);
// ============================================================
// 业务状态指标
// ============================================================
registry.registerMetric(
new promClient.Gauge({
name: "msg_unread_count",
help: "User unread notification count (sampled)",
labelNames: ["user_id"],
}),
);
// 自动收集 Node.js 进程级指标CPU/内存/事件循环/GC等
// 这些指标无需业务代码埋点prom-client 自动采集
promClient.collectDefaultMetrics({ register: registry });
export { registry as metricsRegistry };
// ============================================================
// 便捷访问器:业务代码通过命名导出获取已注册的 Metric 实例
// ============================================================
export const metricsRegistry = registry;
export const httpRequestsTotal = registry.getSingleMetric(
"msg_http_requests_total",
) as promClient.Counter<string>;
export const httpRequestDurationSeconds = registry.getSingleMetric(
"msg_http_request_duration_seconds",
) as promClient.Histogram<string>;
export const grpcRequestsTotal = registry.getSingleMetric(
"msg_grpc_requests_total",
) as promClient.Counter<string>;
export const notificationSentTotal = registry.getSingleMetric(
"msg_notification_sent_total",
) as promClient.Counter<string>;
export const notificationSendDurationSeconds = registry.getSingleMetric(
"msg_notification_send_duration_seconds",
) as promClient.Histogram<string>;
export const notificationFailedTotal = registry.getSingleMetric(
"msg_notification_failed_total",
) as promClient.Counter<string>;
export const notificationReadTotal = registry.getSingleMetric(
"msg_notification_read_total",
) as promClient.Counter<string>;
export const channelDispatchDurationSeconds = registry.getSingleMetric(
"msg_channel_dispatch_duration_seconds",
) as promClient.Histogram<string>;
export const kafkaConsumerLag = registry.getSingleMetric(
"msg_kafka_consumer_lag",
) as promClient.Gauge<string>;
export const kafkaConsumerProcessedTotal = registry.getSingleMetric(
"msg_kafka_consumer_processed_total",
) as promClient.Counter<string>;
export const idempotentDuplicateTotal = registry.getSingleMetric(
"msg_idempotent_duplicate_total",
) as promClient.Counter<string>;
export const outboxPendingCount = registry.getSingleMetric(
"msg_outbox_pending_count",
) as promClient.Gauge<string>;
export const pushGatewayCallTotal = registry.getSingleMetric(
"msg_push_gateway_call_total",
) as promClient.Counter<string>;
export const pushGatewayCallDurationSeconds = registry.getSingleMetric(
"msg_push_gateway_call_duration_seconds",
) as promClient.Histogram<string>;
export const unreadCount = registry.getSingleMetric(
"msg_unread_count",
) as promClient.Gauge<string>;