koatty_serve
Version:
Provide http1/2, websocket, gRPC server for Koatty.
1,845 lines (1,797 loc) • 167 kB
JavaScript
/*!
* @Author: richen
* @Date: 2025-06-17 02:25:44
* @License: BSD (3-Clause)
* @Copyright (c) - <richenlin(at)gmail.com>
* @HomePage: https://koatty.org/
*/
"use strict";
var e = require("@grpc/grpc-js");
var t = require("fs");
var o = require("koatty_logger");
var n = require("perf_hooks");
var i = require("koatty_lib");
var r = require("net");
var s = require("tls");
var c = require("http2");
var a = require("ws");
var l = require("http");
var h = require("https");
function d(e) {
var t = Object.create(null);
if (e) Object.keys(e).forEach((function(o) {
if (o !== "default") {
var n = Object.getOwnPropertyDescriptor(e, o);
Object.defineProperty(t, o, n.get ? n : {
enumerable: !0,
get: function() {
return e[o];
}
});
}
}));
t.default = e;
return Object.freeze(t);
}
var u = d(a);
/*
* @Description: Structured logging utilities based on koatty_logger
* @Usage:
* @Author: richen
* @Date: 2025-01-27 12:00:00
* @License: BSD (3-Clause)
* @Copyright (c): <richenlin(at)gmail.com>
*/ class StructuredLogger {
constructor() {
this.globalContext = {};
this.performanceTrackers = new Map;
}
static getInstance() {
if (!StructuredLogger.instance) StructuredLogger.instance = new StructuredLogger;
return StructuredLogger.instance;
}
setGlobalContext(e) {
this.globalContext = {
...this.globalContext,
...e
};
}
clearGlobalContext() {
this.globalContext = {};
}
formatMessage(e, t, o) {
const n = {
...this.globalContext,
...t
};
const i = [];
if (n.module) i.push(`[${n.module.toUpperCase()}]`);
if (n.protocol) i.push(`[${n.protocol.toUpperCase()}]`);
if (n.serverId) i.push(`[Server:${n.serverId}]`);
if (n.connectionId) i.push(`[Conn:${n.connectionId}]`);
if (n.action) i.push(`[${n.action}]`);
const r = i.length > 0 ? `${i.join(" ")} ` : "";
let s = `${r}${e}`;
if (o) {
const e = typeof o === "object" ? JSON.stringify(o) : String(o);
s += ` | Data: ${e}`;
}
if (n.traceId) s += ` | TraceId: ${n.traceId}`;
return s;
}
debug(e, t, n) {
const i = this.formatMessage(e, t, n);
o.DefaultLogger.Debug(i);
}
info(e, t, n) {
const i = this.formatMessage(e, t, n);
o.DefaultLogger.Info(i);
}
warn(e, t, n) {
const i = this.formatMessage(e, t, n);
o.DefaultLogger.Warn(i);
}
error(e, t, n) {
const i = n instanceof Error ? {
name: n.name,
message: n.message,
stack: n.stack
} : n;
const r = this.formatMessage(e, t, i);
o.DefaultLogger.Error(r);
}
startPerformanceTracking(e, t) {
const o = {
startTime: n.performance.now(),
memoryUsage: process.memoryUsage()
};
this.performanceTrackers.set(e, o);
this.debug(`Performance tracking started`, {
...t,
action: "perf_start"
}, {
trackingId: e
});
}
endPerformanceTracking(e, t) {
const o = this.performanceTrackers.get(e);
if (!o) {
this.warn(`Performance tracking not found`, t, {
trackingId: e
});
return null;
}
o.endTime = n.performance.now();
o.duration = o.endTime - o.startTime;
const i = process.memoryUsage();
const r = {
heapUsed: i.heapUsed - o.memoryUsage.heapUsed,
heapTotal: i.heapTotal - o.memoryUsage.heapTotal,
external: i.external - o.memoryUsage.external
};
this.info(`Performance tracking completed`, {
...t,
action: "perf_end"
}, {
trackingId: e,
duration: `${o.duration.toFixed(2)}ms`,
memoryDiff: r
});
this.performanceTrackers.delete(e);
return o;
}
logServerEvent(e, t, o) {
const n = {
...t,
action: `server_${e}`
};
switch (e) {
case "starting":
this.info(`Server starting`, n, o);
break;
case "started":
this.info(`Server started successfully`, n, o);
break;
case "stopping":
this.info(`Server stopping`, n, o);
break;
case "stopped":
this.info(`Server stopped successfully`, n, o);
break;
case "error":
this.error(`Server error occurred`, n, o);
break;
}
}
logConnectionEvent(e, t, o) {
const n = {
...t,
action: `connection_${e}`
};
switch (e) {
case "connected":
this.info(`Connection established`, n, o);
break;
case "disconnected":
this.info(`Connection closed`, n, o);
break;
case "error":
this.error(`Connection error`, n, o);
break;
case "timeout":
this.warn(`Connection timeout`, n, o);
break;
}
}
logSecurityEvent(e, t, o) {
const n = {
...t,
action: `security_${e}`
};
switch (e) {
case "auth_success":
this.info(`Authentication successful`, n, o);
break;
case "auth_failure":
this.warn(`Authentication failed`, n, o);
break;
case "rate_limit":
this.warn(`Rate limit exceeded`, n, o);
break;
case "blocked":
this.warn(`Request blocked`, n, o);
break;
}
}
createChildLogger(e) {
return new ChildLogger(this, {
...this.globalContext,
...e
});
}
}
class ChildLogger {
constructor(e, t) {
this.parent = e;
this.childContext = t;
}
debug(e, t, o) {
this.parent.debug(e, {
...this.childContext,
...t
}, o);
}
info(e, t, o) {
this.parent.info(e, {
...this.childContext,
...t
}, o);
}
warn(e, t, o) {
this.parent.warn(e, {
...this.childContext,
...t
}, o);
}
error(e, t, o) {
this.parent.error(e, {
...this.childContext,
...t
}, o);
}
logServerEvent(e, t, o) {
this.parent.logServerEvent(e, {
...this.childContext,
...t
}, o);
}
logConnectionEvent(e, t, o) {
this.parent.logConnectionEvent(e, {
...this.childContext,
...t
}, o);
}
logSecurityEvent(e, t, o) {
this.parent.logSecurityEvent(e, {
...this.childContext,
...t
}, o);
}
startPerformanceTracking(e, t) {
this.parent.startPerformanceTracking(e, {
...this.childContext,
...t
});
}
endPerformanceTracking(e, t) {
return this.parent.endPerformanceTracking(e, {
...this.childContext,
...t
});
}
}
const g = StructuredLogger.getInstance();
const p = e => g.createChildLogger(e);
const m = () => `trace_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
/*
* @Description:
* @Usage:
* @Author: richen
* @Date: 2023-12-09 12:02:29
* @LastEditTime: 2024-11-07 11:08:26
* @License: BSD (3-Clause)
* @Copyright (c): <richenlin(at)gmail.com>
*/;
function f(e, t, o = new WeakSet) {
if (e === t) return !0;
if (e == null || t == null) return !1;
if (typeof e !== typeof t) return !1;
if (typeof e === "object") {
if (o.has(e)) return !0;
o.add(e);
const n = Array.isArray(e);
const i = Array.isArray(t);
if (n !== i) return !1;
const r = Object.keys(e);
const s = Object.keys(t);
if (r.length !== s.length) return !1;
const c = r.every((n => f(e[n], t[n], o)));
o.delete(e);
return c;
}
return !1;
}
function v(e) {
return `${e}_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
}
/*
* @Description: 统一定时器管理器
* @Usage: 解决定时器资源泄漏问题,统一管理所有定时器
* @Author: richen
* @Date: 2024-11-27 20:30:00
* @LastEditTime: 2024-11-27 20:30:00
*/ var C;
(function(e) {
e[e["HIGH"] = 5e3] = "HIGH";
e[e["MEDIUM"] = 3e4] = "MEDIUM";
e[e["LOW"] = 6e4] = "LOW";
})(C || (C = {}));
class TimerManager {
constructor(e = {}) {
this.timers = new Map;
this.timerIdCounter = 0;
this.logger = p({
module: "timer_manager"
});
this.taskQueues = new Map;
this.consolidatedTimers = new Map;
this.performanceMetrics = {
totalTasks: 0,
executedTasks: 0,
averageExecutionTime: 0,
lastOptimization: Date.now()
};
this.optimizerConfig = {
enableConsolidation: !0,
enableAdaptiveFrequency: !0,
maxTimersPerFrequency: 10,
loadThreshold: .7,
...e
};
Object.values(C).forEach((e => {
if (typeof e === "number") this.taskQueues.set(e, []);
}));
this.logger.info("Timer manager initialized with optimization", {}, {
config: this.optimizerConfig,
supportedFrequencies: Object.values(C).filter((e => typeof e === "number"))
});
}
addTimer(e, t, o) {
return this.addOptimizedTimer({
name: e,
callback: t,
interval: o,
priority: this.determinePriority(o),
protocol: this.extractProtocol(e)
});
}
addOptimizedTimer(e) {
const t = `${e.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const o = {
...e,
id: t,
lastExecuted: 0,
executionCount: 0
};
const n = this.selectOptimalFrequency(e.interval);
const i = this.taskQueues.get(n);
if (i) {
i.push(o);
this.performanceMetrics.totalTasks++;
this.optimizeTimers();
}
return t;
}
createPhysicalTimer(e, t, o) {
const n = `${e}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const i = () => {
try {
t();
} catch (t) {
this.logger.error("Timer callback error", {
name: e,
timerId: n,
error: t instanceof Error ? t.message : String(t)
});
}
};
const r = setInterval(i, o);
if (typeof r.unref === "function") r.unref();
const s = {
id: n,
name: e,
interval: o,
callback: i,
timer: r,
createdAt: Date.now(),
lastExecuted: Date.now()
};
this.timers.set(n, s);
return n;
}
clearTimer(e) {
for (const [t, o] of this.taskQueues) {
const t = o.findIndex((t => t.id === e || t.name === e));
if (t !== -1) {
this.performanceMetrics.totalTasks--;
this.optimizeTimers();
return !0;
}
}
const t = this.timers.get(e);
if (t) {
clearInterval(t.timer);
this.timers.delete(e);
return !0;
}
this.logger.warn(`Timer '${e}' not found for clearing`);
return !1;
}
clearAllTimers() {
const e = this.performanceMetrics.totalTasks;
const t = this.timers.size;
this.logger.info(`Clearing all timers`, {}, {
logicalTimers: e,
physicalTimers: t
});
this.taskQueues.clear();
this.performanceMetrics.totalTasks = 0;
this.performanceMetrics.executedTasks = 0;
Object.values(C).forEach((e => {
if (typeof e === "number") this.taskQueues.set(e, []);
}));
for (const [e, t] of this.timers) try {
clearInterval(t.timer);
} catch (t) {
this.logger.error(`Error clearing timer '${e}':`, {}, t);
}
this.timers.clear();
this.consolidatedTimers.clear();
this.logger.info(`All timers cleared successfully`, {}, {
clearedLogicalTimers: e,
clearedPhysicalTimers: t
});
}
getActiveTimerCount() {
return this.performanceMetrics.totalTasks;
}
getTimerNames() {
const e = [];
for (const t of this.taskQueues.values()) e.push(...t.map((e => e.name)));
return e;
}
getTimerInfo(e) {
return this.timers.get(e);
}
getTimerStats() {
const e = Date.now();
const t = [];
for (const o of this.taskQueues.values()) for (const n of o) t.push({
id: n.id,
name: n.name,
interval: n.interval,
uptime: e - (n.lastExecuted || e),
lastExecuted: n.lastExecuted,
priority: n.priority,
executionCount: n.executionCount || 0
});
return {
totalTimers: this.performanceMetrics.totalTasks,
timers: t
};
}
hasTimer(e) {
for (const t of this.taskQueues.values()) if (t.some((t => t.id === e))) return !0;
return this.timers.has(e);
}
determinePriority(e) {
if (e <= 5e3) return "high";
if (e <= 3e4) return "medium";
return "low";
}
extractProtocol(e) {
const t = e.match(/^(http|https|http2|grpc|websocket|ws)/i);
return t ? t[1].toLowerCase() : void 0;
}
selectOptimalFrequency(e) {
const t = [ C.HIGH, C.MEDIUM, C.LOW ];
for (const o of t) if (e <= o) return o;
return C.LOW;
}
optimizeTimers() {
this.clearConsolidatedTimers();
for (const [e, t] of this.taskQueues) if (t.length > 0) this.createConsolidatedTimer(e, t);
this.performanceMetrics.lastOptimization = Date.now();
}
createConsolidatedTimer(e, t) {
const o = `consolidated_${e}ms`;
const n = this.createPhysicalTimer(o, (() => {
this.executeTaskBatch(e, t);
}), e);
this.consolidatedTimers.set(e, n);
}
executeTaskBatch(e, t) {
let o = 0;
const n = t.sort(((e, t) => {
const o = {
high: 3,
medium: 2,
low: 1
};
return o[t.priority] - o[e.priority];
}));
for (const t of n) try {
const n = Date.now();
if (this.shouldExecuteTask(t, e)) {
t.callback();
t.lastExecuted = Date.now();
t.executionCount = (t.executionCount || 0) + 1;
o++;
const e = Date.now() - n;
this.updateAverageExecutionTime(e);
}
} catch (e) {
this.logger.error("Task execution error", {}, {
taskId: t.id,
taskName: t.name,
error: e instanceof Error ? e.message : String(e)
});
}
this.performanceMetrics.executedTasks += o;
}
shouldExecuteTask(e, t) {
if (!this.optimizerConfig.enableAdaptiveFrequency) return !0;
if (e.priority === "high") return !0;
const o = e.interval / t;
if (o <= 1) return !0;
const n = Date.now() - (e.lastExecuted || 0);
return n >= e.interval;
}
updateAverageExecutionTime(e) {
const t = .1;
this.performanceMetrics.averageExecutionTime = this.performanceMetrics.averageExecutionTime * (1 - t) + e * t;
}
clearConsolidatedTimers() {
for (const e of this.consolidatedTimers.values()) this.clearTimer(e);
this.consolidatedTimers.clear();
}
getOptimizationStats() {
const e = new Map;
const t = {
high: 0,
medium: 0,
low: 0
};
for (const [o, n] of this.taskQueues) {
e.set(o, n.length);
for (const e of n) t[e.priority]++;
}
return {
performance: this.performanceMetrics,
consolidation: {
activeTimers: this.consolidatedTimers.size,
totalTasks: this.performanceMetrics.totalTasks,
tasksByFrequency: Object.fromEntries(e),
tasksByPriority: t
},
config: this.optimizerConfig
};
}
static createOptimizedInstance() {
return new TimerManager({
enableConsolidation: !0,
enableAdaptiveFrequency: !0,
maxTimersPerFrequency: 10,
loadThreshold: .7
});
}
demonstrateOptimization() {
const e = [ 5e3, 5e3, 3e4, 3e4, 3e4, 6e4, 6e4 ];
const t = [ C.HIGH, C.MEDIUM, C.LOW ];
const o = ((e.length - t.length) / e.length * 100).toFixed(1);
return {
before: {
timerCount: e.length,
intervals: e
},
after: {
consolidatedTimers: t.length,
frequencies: t,
estimatedReduction: `${o}% timer reduction`
}
};
}
destroy() {
this.logger.info("TimerManager destroying", {}, {
activeTimers: this.timers.size,
totalTasks: this.performanceMetrics.totalTasks,
executedTasks: this.performanceMetrics.executedTasks,
activeConsolidatedTimers: this.consolidatedTimers.size
});
this.clearConsolidatedTimers();
this.taskQueues.clear();
this.clearAllTimers();
this.logger.info("TimerManager destroyed successfully");
}
}
new TimerManager({
enableConsolidation: !0,
enableAdaptiveFrequency: !0,
maxTimersPerFrequency: 10,
loadThreshold: .7
});
/*
* @Description: 统一连接池监控管理器
* @Usage: 合并监控定时器,替代多个独立定时器,优化性能
* @Author: richen
* @Date: 2024-11-27 20:30:00
* @LastEditTime: 2024-11-27 20:30:00
*/ class UnifiedPoolMonitor {
constructor(e, t = 5e3) {
this.protocol = e;
this.logger = p({
module: "unified_monitor"
});
this.tasks = new Map;
this.taskStats = new Map;
this.monitoringInterval = 5e3;
this.isRunning = !1;
this.startTime = 0;
this.lastExecutionTimes = new Map;
this.timerManager = new TimerManager;
this.monitoringInterval = t;
}
registerTask(e) {
if (this.tasks.has(e.name)) this.logger.warn("Monitoring task already exists, replacing", {}, {
taskName: e.name,
protocol: this.protocol
});
const t = {
...e,
enabled: e.enabled !== !1,
description: e.description || `Monitoring task: ${e.name}`
};
this.tasks.set(e.name, t);
this.taskStats.set(e.name, {
tasksExecuted: 0,
tasksSuccessful: 0,
tasksFailed: 0,
lastExecutionTime: 0,
averageExecutionTime: 0,
uptime: 0
});
}
unregisterTask(e) {
if (this.tasks.delete(e)) {
this.taskStats.delete(e);
this.lastExecutionTimes.delete(e);
}
}
setTaskEnabled(e, t) {
const o = this.tasks.get(e);
if (o) o.enabled = t;
}
startMonitoring() {
if (this.isRunning) {
this.logger.warn("Unified monitoring already running", {}, {
protocol: this.protocol
});
return;
}
this.isRunning = !0;
this.startTime = Date.now();
this.timerManager.addTimer("unified_monitoring", (() => {
this.executeMonitoringCycle();
}), this.monitoringInterval);
this.logger.info("Unified monitoring started", {}, {
interval: this.monitoringInterval,
tasksCount: this.tasks.size,
protocol: this.protocol
});
}
stopMonitoring() {
if (!this.isRunning) return;
this.isRunning = !1;
this.timerManager.destroy();
this.logger.info("Unified monitoring stopped", {}, {
protocol: this.protocol,
uptime: Date.now() - this.startTime
});
}
async executeMonitoringCycle() {
const e = Date.now();
const t = m();
const o = this.getTasksToExecute(e);
if (o.length === 0) return;
const n = this.groupTasksByPriority(o);
for (const [e, o] of n) await this.executePriorityGroup(o, e, t);
}
getTasksToExecute(e) {
const t = [];
for (const [o, n] of this.tasks) {
if (!n.enabled) continue;
const i = this.lastExecutionTimes.get(o) || 0;
if (e - i >= n.interval) t.push(n);
}
return t.sort(((e, t) => e.priority - t.priority));
}
groupTasksByPriority(e) {
const t = new Map;
for (const o of e) {
const e = o.priority;
if (!t.has(e)) t.set(e, []);
t.get(e).push(o);
}
return t;
}
async executePriorityGroup(e, t, o) {
const n = e.map((e => this.executeTask(e, o)));
await Promise.allSettled(n);
}
async executeTask(e, t) {
const o = Date.now();
const n = this.taskStats.get(e.name);
try {
await e.execute();
const t = Date.now() - o;
this.lastExecutionTimes.set(e.name, o);
n.tasksExecuted++;
n.tasksSuccessful++;
n.lastExecutionTime = t;
n.averageExecutionTime = this.calculateAverageExecutionTime(n, t);
n.uptime = Date.now() - this.startTime;
return {
taskName: e.name,
success: !0,
executionTime: t,
timestamp: o
};
} catch (i) {
const r = Date.now() - o;
n.tasksExecuted++;
n.tasksFailed++;
n.lastExecutionTime = r;
n.uptime = Date.now() - this.startTime;
if (e.onError) try {
e.onError(i);
} catch (o) {
this.logger.error(`Task error handler failed: ${e.name}`, {
traceId: t
}, o);
}
this.logger.error(`Task execution failed: ${e.name}`, {
traceId: t
}, i);
return {
taskName: e.name,
success: !1,
executionTime: r,
error: i,
timestamp: o
};
}
}
calculateAverageExecutionTime(e, t) {
if (e.tasksExecuted === 1) return t;
const o = .1;
return e.averageExecutionTime * (1 - o) + t * o;
}
getTaskStats(e) {
if (e) return this.taskStats.get(e) || {
tasksExecuted: 0,
tasksSuccessful: 0,
tasksFailed: 0,
lastExecutionTime: 0,
averageExecutionTime: 0,
uptime: 0
};
return new Map(this.taskStats);
}
getMonitorStatus() {
let e = 0;
let t = 0;
let o = 0;
for (const n of this.taskStats.values()) {
e += n.tasksExecuted;
t += n.tasksSuccessful;
o += n.tasksFailed;
}
const n = Array.from(this.tasks.values()).filter((e => e.enabled)).length;
return {
isRunning: this.isRunning,
uptime: this.isRunning ? Date.now() - this.startTime : 0,
tasksCount: this.tasks.size,
enabledTasksCount: n,
totalExecutions: e,
totalSuccesses: t,
totalFailures: o
};
}
getTasks() {
return Array.from(this.tasks.entries()).map((([e, t]) => ({
name: e,
interval: t.interval,
priority: t.priority,
enabled: t.enabled || !1,
description: t.description || "",
stats: this.taskStats.get(e) || {
tasksExecuted: 0,
tasksSuccessful: 0,
tasksFailed: 0,
lastExecutionTime: 0,
averageExecutionTime: 0,
uptime: 0
}
})));
}
destroy() {
this.stopMonitoring();
this.tasks.clear();
this.taskStats.clear();
this.lastExecutionTimes.clear();
}
}
class MonitoringTaskFactory {
static createHealthCheckTask(e, t = 5e3) {
return {
name: "health_check",
interval: t,
priority: 1,
execute: e,
description: "Pool health check monitoring"
};
}
static createCleanupTask(e, t = 3e4) {
return {
name: "cleanup_expired",
interval: t,
priority: 3,
execute: e,
description: "Cleanup expired connections"
};
}
static createPingTask(e, t = 3e4, o = "generic") {
return {
name: `${o}_ping`,
interval: t,
priority: 2,
execute: e,
description: `${o.toUpperCase()} ping monitoring`
};
}
static createHeartbeatTask(e, t = 2e4) {
return {
name: "heartbeat",
interval: t,
priority: 2,
execute: e,
description: "Connection heartbeat monitoring"
};
}
static createSecurityMonitoringTask(e, t = 6e4) {
return {
name: "security_monitoring",
interval: t,
priority: 4,
execute: e,
description: "Security monitoring and analysis"
};
}
static createMetricsCollectionTask(e, t = 1e4) {
return {
name: "metrics_collection",
interval: t,
priority: 5,
execute: e,
description: "Performance metrics collection"
};
}
}
/*
* @Description: 统一连接池管理接口
* @Usage: 为各协议提供统一的连接池管理接口
* @Author: richen
* @Date: 2024-11-27 20:30:00
* @LastEditTime: 2024-11-27 20:30:00
*/ var S;
(function(e) {
e["HEALTHY"] = "healthy";
e["DEGRADED"] = "degraded";
e["OVERLOADED"] = "overloaded";
e["UNAVAILABLE"] = "unavailable";
})(S || (S = {}));
var T;
(function(e) {
e["CONNECTION_ADDED"] = "connection_added";
e["CONNECTION_REMOVED"] = "connection_removed";
e["CONNECTION_TIMEOUT"] = "connection_timeout";
e["CONNECTION_ERROR"] = "connection_error";
e["POOL_LIMIT_REACHED"] = "pool_limit_reached";
e["HEALTH_STATUS_CHANGED"] = "health_status_changed";
})(T || (T = {}));
class ConnectionPoolManager {
constructor(e, t = {}) {
this.logger = p({
module: "connection_pool"
});
this.startTime = Date.now();
this.eventListeners = new Map;
this.connections = new Map;
this.connectionMetadata = new Map;
this.waitingQueue = [];
this.latencyBuffer = [];
this.lastMetricsUpdate = Date.now();
this.protocol = e;
this.config = this.validateAndNormalizeConfig(t);
this.logger = p({
module: "connection_pool",
protocol: this.protocol
});
this.metrics = this.initializeMetrics();
this.currentHealth = this.initializeHealth();
this.timerManager = new TimerManager;
this.unifiedMonitor = new UnifiedPoolMonitor(this.protocol, 5e3);
this.setupUnifiedMonitoring();
this.logger.info("Connection pool manager initialized", {}, {
protocol: this.protocol,
config: this.config
});
}
initializeMetrics() {
return {
protocol: this.protocol,
activeConnections: 0,
totalConnections: 0,
connectionsPerSecond: 0,
averageLatency: 0,
errorRate: 0,
poolConfig: this.config,
health: this.currentHealth,
performance: {
throughput: 0,
latency: {
p50: 0,
p95: 0,
p99: 0
},
memoryUsage: 0,
cpuUsage: 0
},
uptime: 0
};
}
initializeHealth() {
return {
status: S.HEALTHY,
utilizationRatio: 0,
activeConnections: 0,
maxConnections: this.config.maxConnections || 1e3,
rejectedConnections: 0,
averageResponseTime: 0,
errorRate: 0,
message: "Connection pool is healthy",
lastUpdated: Date.now()
};
}
validateAndNormalizeConfig(e) {
const t = {
maxConnections: e.maxConnections || 1e3,
connectionTimeout: e.connectionTimeout || 3e4,
keepAliveTimeout: e.keepAliveTimeout || 5e3,
requestTimeout: e.requestTimeout || 3e4,
headersTimeout: e.headersTimeout || 1e4,
...e
};
if (t.maxConnections && t.maxConnections <= 0) throw new Error("maxConnections must be positive");
if (t.connectionTimeout && t.connectionTimeout <= 0) throw new Error("connectionTimeout must be positive");
return t;
}
async requestConnection(e = {}) {
const t = Date.now();
const o = e.timeout || this.config.connectionTimeout || 3e4;
try {
if (!this.canAcceptConnection()) {
this.currentHealth.rejectedConnections++;
this.emitEvent(T.POOL_LIMIT_REACHED, {
currentConnections: this.getActiveConnectionCount(),
maxConnections: this.config.maxConnections
});
return {
connection: null,
success: !1,
error: new Error("Connection pool limit reached"),
waitTime: Date.now() - t
};
}
const n = await this.getAvailableConnection();
if (n) return {
connection: n.connection,
success: !0,
waitTime: Date.now() - t,
connectionId: n.id
};
const i = await this.createNewConnection(e);
if (i) {
await this.addConnection(i.connection, i.metadata);
return {
connection: i.connection,
success: !0,
waitTime: Date.now() - t,
connectionId: i.id
};
}
return new Promise(((n, i) => {
const r = setTimeout((() => {
const e = this.waitingQueue.findIndex((e => e.resolve === n));
if (e >= 0) this.waitingQueue.splice(e, 1);
n({
connection: null,
success: !1,
error: new Error("Connection request timeout"),
waitTime: Date.now() - t
});
}), o);
this.waitingQueue.push({
resolve: e => {
clearTimeout(r);
n(e);
},
reject: e => {
clearTimeout(r);
i(e);
},
options: e,
timestamp: t
});
this.waitingQueue.sort(((e, t) => {
const o = {
low: 1,
normal: 2,
high: 3
};
const n = o[e.options.priority || "normal"];
const i = o[t.options.priority || "normal"];
return i - n;
}));
}));
} catch (e) {
this.recordConnectionEvent("error", {
error: e
});
return {
connection: null,
success: !1,
error: e,
waitTime: Date.now() - t
};
}
}
async releaseConnection(e, t = {}) {
var o;
const n = m();
try {
const i = this.findConnectionId(e);
if (!i) {
this.logger.warn("Attempting to release unknown connection", {
traceId: n
});
return !1;
}
if (t.destroy || t.error) await this.removeConnection(e, ((o = t.error) === null || o === void 0 ? void 0 : o.message) || "Explicitly destroyed"); else this.markConnectionAvailable(i);
await this.processWaitingQueue();
return !0;
} catch (e) {
this.logger.error("Failed to release connection", {
traceId: n
}, e);
return !1;
}
}
async addConnection(e, t = {}) {
const o = this.generateConnectionId();
try {
if (!this.validateConnection(e)) throw new Error("Invalid connection");
if (!this.canAcceptConnection()) throw new Error("Connection pool limit reached");
this.connections.set(o, e);
this.connectionMetadata.set(o, {
...t,
id: o,
createdAt: Date.now(),
lastUsed: Date.now(),
available: t.available !== void 0 ? t.available : !0
});
this.recordConnectionEvent("added", {
connectionId: o,
metadata: t
});
this.emitEvent(T.CONNECTION_ADDED, {
connectionId: o,
connection: e
});
return !0;
} catch (e) {
this.logger.error("Failed to add connection to pool", {}, e);
return !1;
}
}
async removeConnection(e, t) {
const o = this.findConnectionId(e);
if (!o) return;
try {
await this.cleanupConnection(e);
this.connections.delete(o);
this.connectionMetadata.delete(o);
this.recordConnectionEvent("removed", {
connectionId: o,
reason: t
});
this.emitEvent(T.CONNECTION_REMOVED, {
connectionId: o,
reason: t
});
} catch (e) {
this.logger.error("Error removing connection from pool", {}, e);
}
}
getActiveConnectionCount() {
return this.connections.size;
}
async closeAllConnections(e = 5e3) {
const t = m();
this.logger.info("Closing all connections", {
traceId: t
}, {
activeConnections: this.connections.size
});
const o = [];
for (const [e, n] of this.connections) o.push(this.removeConnection(n, "Pool shutdown").catch((o => {
this.logger.error("Error closing connection", {
traceId: t
}, {
connectionId: e,
error: o
});
})));
try {
await Promise.race([ Promise.all(o), new Promise(((t, o) => setTimeout((() => o(new Error("Close timeout"))), e))) ]);
} catch (e) {
this.logger.warn("Some connections failed to close gracefully", {
traceId: t
}, e);
}
this.connections.clear();
this.connectionMetadata.clear();
this.logger.info("All connections closed", {
traceId: t
});
}
async createNewConnection(e) {
const t = await this.createProtocolConnection(e);
if (t) return {
connection: t.connection,
id: this.generateConnectionId(),
metadata: t.metadata
};
return null;
}
canAcceptConnection() {
const e = this.config.maxConnections;
if (!e) return !0;
const t = this.getActiveConnectionCount();
return t < e;
}
updateHealthStatus() {
const e = this.getActiveConnectionCount();
const t = this.config.maxConnections || 1 / 0;
const o = t === 1 / 0 ? 0 : e / t;
let n = S.HEALTHY;
let i = "Connection pool is healthy";
if (o > .95) {
n = S.OVERLOADED;
i = "Connection pool is overloaded";
} else if (o > .8) {
n = S.DEGRADED;
i = "Connection pool is under high load";
}
const r = this.currentHealth.status;
this.currentHealth = {
...this.currentHealth,
status: n,
utilizationRatio: o,
activeConnections: e,
maxConnections: t === 1 / 0 ? 0 : t,
message: i,
lastUpdated: Date.now()
};
this.metrics.health = this.currentHealth;
if (r !== n) this.emitEvent(T.HEALTH_STATUS_CHANGED, {
oldStatus: r,
newStatus: n,
health: this.currentHealth
});
}
getHealth() {
this.updateHealthStatus();
return {
...this.currentHealth
};
}
getMetrics() {
const e = Date.now() - this.startTime;
this.updatePerformanceMetrics();
return {
...this.metrics,
uptime: e,
health: this.getHealth(),
activeConnections: this.getActiveConnectionCount()
};
}
getConfig() {
return {
...this.config
};
}
async updateConfig(e) {
const t = m();
try {
this.logger.info("Updating connection pool configuration", {
traceId: t
}, {
oldConfig: this.config,
newConfig: e
});
const o = this.validateAndNormalizeConfig({
...this.config,
...e
});
Object.assign(this.config, o);
this.metrics.poolConfig = this.config;
this.logger.info("Connection pool configuration updated successfully", {
traceId: t
});
return !0;
} catch (e) {
this.logger.error("Failed to update connection pool configuration", {
traceId: t
}, e);
return !1;
}
}
on(e, t) {
if (!this.eventListeners.has(e)) this.eventListeners.set(e, new Set);
this.eventListeners.get(e).add(t);
}
off(e, t) {
const o = this.eventListeners.get(e);
if (o) o.delete(t);
}
generateConnectionId() {
return `${this.protocol}_${Date.now()}_${Math.random().toString(36).substr(2, 8)}`;
}
findConnectionId(e) {
for (const [t, o] of this.connections) if (o === e) return t;
return null;
}
markConnectionAvailable(e) {
const t = this.connectionMetadata.get(e);
if (t) {
t.available = !0;
t.lastUsed = Date.now();
}
}
async processWaitingQueue() {
while (this.waitingQueue.length > 0 && this.canAcceptConnection()) {
const e = this.waitingQueue.shift();
if (!e) break;
try {
const t = await this.requestConnection(e.options);
e.resolve(t);
} catch (t) {
e.reject(t);
}
}
}
updatePerformanceMetrics() {
const e = Date.now();
const t = (e - this.lastMetricsUpdate) / 1e3;
if (t > 0) {
this.metrics.connectionsPerSecond = this.metrics.totalConnections / ((e - this.startTime) / 1e3);
this.metrics.performance.throughput = this.metrics.totalConnections / t;
}
if (this.latencyBuffer.length > 0) {
const e = this.latencyBuffer.sort(((e, t) => e - t));
const t = e.length;
this.metrics.performance.latency.p50 = e[Math.floor(t * .5)];
this.metrics.performance.latency.p95 = e[Math.floor(t * .95)];
this.metrics.performance.latency.p99 = e[Math.floor(t * .99)];
this.metrics.averageLatency = e.reduce(((e, t) => e + t)) / t;
if (this.latencyBuffer.length > 1e3) this.latencyBuffer = this.latencyBuffer.slice(-500);
}
this.lastMetricsUpdate = e;
}
setupUnifiedMonitoring() {
const e = MonitoringTaskFactory.createHealthCheckTask((() => this.updateHealthStatus()), 5e3);
this.unifiedMonitor.registerTask(e);
const t = MonitoringTaskFactory.createCleanupTask((() => this.cleanupExpiredConnections()), 3e4);
this.unifiedMonitor.registerTask(t);
this.unifiedMonitor.startMonitoring();
}
cleanupExpiredConnections() {
const e = Date.now();
const t = this.config.connectionTimeout || 3e4;
const o = [];
for (const [n, i] of this.connectionMetadata) if (i.available && e - i.lastUsed > t) {
const e = this.connections.get(n);
if (e) o.push({
id: n,
connection: e
});
}
o.forEach((({connection: e}) => {
this.removeConnection(e, "Connection expired").catch((e => {
this.logger.error("Error cleaning up expired connection", {}, e);
}));
}));
}
emitEvent(e, t) {
const o = this.eventListeners.get(e);
if (o) o.forEach((e => {
try {
e(t);
} catch (e) {
this.logger.error("Error in connection pool event listener", {}, e);
}
}));
}
recordConnectionEvent(e, t) {
const o = Date.now();
switch (e) {
case "added":
this.metrics.totalConnections++;
this.metrics.activeConnections = this.getActiveConnectionCount();
break;
case "removed":
this.metrics.activeConnections = this.getActiveConnectionCount();
break;
case "error":
this.metrics.errorRate = Math.min(this.metrics.errorRate + .01, 1);
break;
}
const n = (o - this.startTime) / 1e3;
if (n > 0) this.metrics.connectionsPerSecond = this.metrics.totalConnections / n;
}
recordLatency(e) {
this.latencyBuffer.push(e);
}
async destroy() {
const e = m();
this.logger.info("Destroying connection pool manager", {
traceId: e
});
try {
this.timerManager.destroy();
this.unifiedMonitor.destroy();
this.waitingQueue.forEach((e => {
e.resolve({
connection: null,
success: !1,
error: new Error("Connection pool is being destroyed"),
waitTime: Date.now() - e.timestamp
});
}));
this.waitingQueue = [];
await this.closeAllConnections(5e3);
this.eventListeners.clear();
this.logger.info("Connection pool manager destroyed successfully", {
traceId: e
});
} catch (t) {
this.logger.error("Error destroying connection pool manager", {
traceId: e
}, t);
throw t;
}
}
async getConnection(e = {}) {
return this.requestConnection(e);
}
async registerConnection(e, t = {}) {
if (!this.canAcceptConnection()) return !1;
const o = await this.addConnection(e, t);
if (o) await this.setupProtocolSpecificHandlers(e);
return o;
}
}
/*
* @Description: 统一优雅关闭逻辑
* @Usage: 解决各服务器类优雅关闭步骤的代码重复问题
* @Author: richen
* @Date: 2024-11-27 20:30:00
* @LastEditTime: 2024-11-27 20:30:00
*/ var y;
(function(e) {
e["NOT_STARTED"] = "not_started";
e["IN_PROGRESS"] = "in_progress";
e["DRAINING"] = "draining";
e["COMPLETING"] = "completing";
e["COMPLETED"] = "completed";
e["FAILED"] = "failed";
e["FORCED"] = "forced";
})(y || (y = {}));
class GracefulShutdownManager {
constructor(e) {
this.protocol = e;
this.isShuttingDown = !1;
this.shutdownStartTime = 0;
this.logger = p({
module: "graceful-shutdown"
});
this.currentStatus = {
isInProgress: !1,
currentStep: "",
startTime: 0,
completedSteps: [],
failedSteps: []
};
this.logger = p({
module: "graceful-shutdown",
protocol: this.protocol
});
}
isInShutdown() {
return this.isShuttingDown;
}
getStatus() {
if (!this.currentStatus.isInProgress) return y.NOT_STARTED;
return y.IN_PROGRESS;
}
async performGracefulShutdown(e, t = {}) {
if (this.isShuttingDown) throw new Error("Graceful shutdown already in progress");
this.isShuttingDown = !0;
this.shutdownStartTime = Date.now();
this.currentStatus = {
isInProgress: !0,
currentStep: "",
startTime: this.shutdownStartTime,
completedSteps: [],
failedSteps: []
};
const o = t.timeout || 3e4;
const n = t.drainDelay || 5e3;
this.logger.info("Graceful shutdown initiated", {}, {
protocol: this.protocol,
totalSteps: e.length,
timeout: o,
drainDelay: n
});
try {
const t = await this.executeWithGlobalTimeout((() => this.executeShutdownSteps(e, n)), o);
const i = Date.now() - this.shutdownStartTime;
this.logger.info("Graceful shutdown completed", {}, {
status: t.status,
totalTime: i,
completedSteps: t.completedSteps.length,
failedSteps: t.failedSteps.length
});
return {
...t,
totalTime: i
};
} catch (e) {
const t = Date.now() - this.shutdownStartTime;
this.logger.error("Graceful shutdown failed", {}, {
error: e instanceof Error ? e.message : String(e),
totalTime: t
});
return {
status: y.FAILED,
completedSteps: this.currentStatus.completedSteps,
failedSteps: [ ...this.currentStatus.failedSteps, {
step: "global",
error: e instanceof Error ? e.message : String(e),
timestamp: Date.now()
} ],
totalTime: t
};
} finally {
this.isShuttingDown = !1;
this.currentStatus.isInProgress = !1;
}
}
async executeShutdownStep(e, t, o, n) {
const i = e.timeout || t;
const r = e.retryCount || 0;
let s = 0;
this.logger.info(`Executing shutdown step: ${e.name}`, {
traceId: o
}, {
description: e.description,
timeout: i,
isRequired: e.isRequired !== !1
});
while (s <= r) try {
await this.executeWithTimeout((() => e.execute(o)), i, `Shutdown step: ${e.name}`);
n.completedSteps.push(e.name);
this.logger.debug(`Shutdown step completed: ${e.name}`, {
traceId: o
});
return;
} catch (t) {
s++;
if (s <= r) {
this.logger.warn(`Shutdown step ${e.name} failed, retrying (${s}/${r})`, {
traceId: o
}, t);
await new Promise((e => setTimeout(e, 1e3 * s)));
} else {
n.failedSteps.push({
step: e.name,
error: t,
timestamp: Date.now()
});
if (e.isRequired !== !1) {
this.logger.error(`Required shutdown step failed: ${e.name}`, {
traceId: o
}, t);
throw t;
} else this.logger.warn(`Optional shutdown step failed: ${e.name}`, {
traceId: o
}, t);
}
}
}
async performDrainDelay(e, t) {
this.currentStatus.isInProgress = !0;
this.logger.info("Starting drain delay", {
traceId: t
}, {
drainDelay: e
});
await new Promise((t => setTimeout(t, e)));
this.logger.debug("Drain delay completed", {
traceId: t
});
}
setupForceShutdownTimer(e, t, o) {}
async executeWithTimeout(e, t, o) {
return new Promise(((n, i) => {
const r = setTimeout((() => {
i(new Error(`${o} timed out after ${t}ms`));
}), t);
e().then((e => {
clearTimeout(r);
n(e);
})).catch((e => {
clearTimeout(r);
i(e);
}));
}));
}
createFailedResult(e) {
return {
status: y.FAILED,
totalTime: 0,
completedSteps: [],
failedSteps: [ {
step: "initialization",
error: e,
timestamp: Date.now()
} ]
};
}
cleanup() {}
async executeShutdownSteps(e, t) {
const o = m();
for (const t of e) {
this.currentStatus.currentStep = t.name;
try {
await this.executeWithTimeout((() => t.execute(o)), t.timeout || 5e3, t.name);
this.currentStatus.completedSteps.push(t.name);
} catch (e) {
this.currentStatus.failedSteps.push({
step: t.name,
error: e instanceof Error ? e.message : String(e),
timestamp: Date.now()
});
if (t.isRequired !== !1) throw e;
}
}
if (t > 0) await new Promise((e => setTimeout(e, t)));
return {
status: y.COMPLETED,
completedSteps: this.currentStatus.completedSteps,
failedSteps: this.currentStatus.failedSteps,
totalTime: 0
};
}
async executeWithGlobalTimeout(e, t) {
return new Promise(((o, n) => {
const i = setTimeout((() => {
n(new Error(`Global timeout of ${t}ms exceeded`));
}), t);
e().then((e => {
clearTimeout(i);
o(e);
})).catch((e => {
clearTimeout(i);
n(e);
}));
}));
}
}
class ShutdownStepFactory {
static createStopAcceptingStep(e, t = 5e3) {
return {
name: "stop_accepting_connections",
description: "Stop accepting new connections",
timeout: t,
execute: e,
isRequired: !0
};
}
static createWaitConnectionsStep(e, t = 15e3) {
return {
name: "wait_connections_completion",
description: "Wait for existing connections to complete",
timeout: t,
execute: o => e(t, o),
isRequired: !0,
retryCount: 1
};
}
static createForceCloseStep(e, t = 5e3) {
return {
name: "force_close_connections",
description: "Force close remaining connections",
timeout: t,
execute: e,
isRequired: !0
};
}
static createStopMonitoringStep(e, t = 3e3) {
return {
name: "stop_monitoring_cleanup",
description: "Stop monitoring and cleanup resources",
timeout: t,
execute: async t => e(t),
isRequired: !1
};
}
static createProtocolShutdownStep(e, t, o = 3e3) {
return {
name: `${t}_force_shutdown`,
description: `Force shutdown ${t} specific resources`,
timeout: o,
execute: async t => e(t),
isRequired: !0
};
}
}
/*
* @Description: Base server class with template method pattern for protocol servers
* @Usage: 模板方法模式的基类,定义服务器生命周期的公共逻辑
* @Author: richen
* @Date: 2025-04-08 10:45:00
* @LastEditTime: 2024-11-27 23:00:00
* @License: BSD (3-Clause)
*/ class BaseServer {
constructor(e, t) {
this.app = e;
this.configVersion = 0;
this.logger = p({
module: "base"
});
this.shutdownTimeout = 3e4;
this.drainDelay = 5e3;
this.options = {
...t
};
this.protocol = t.protocol;
this.status = 0;
this.serverId = v(t.protocol);
this.timerManager = new TimerManager;
this.shutdownManager = new GracefulShutdownManager(this.protocol);
this.logger = p({
module: t.protocol,
protocol: t.protocol,
serverId: this.serverId
});
this.logger.debug(`${t.protocol} server constructed`, {}, {
protocol: t.protocol,
hostname: t.hostname,
port: t.port,
serverId: this.serverId
});
this.initializeServer();
}
initializeServer() {
this.logger.info("Initializing server", {}, {
protocol: this.protocol,
serverId: this.serverId
});
try {
this.initializeConnectionPool();
this.createProtocolServer();
this.configureServerOptions();
this.setupConnectionPoolEventListeners();
this.setupPeriodicCleanup();
this.performProtocolSpecificInitialization();
this.logger.debug("Server initialized successfully");
} catch (e) {
this.logger.error("Server initialization failed", {}, e);
throw e;
}
}
async updateConfig(e) {
const t = m();
const o = {
...this.options
};
const n = {
...this.options,
...e
};
const i = this.detectConfigurationChanges(o, e);
if (i.length === 0) {
this.logger.debug("No configuration changes detected", {
traceId: t
});
return !1;
}
this.logger.info("Configuration update initiated", {
traceId: t
}, {
changedKeys: i.map(String),
oldConfig: this.extractRelevantConfig(o),
newConfig: this.extractRelevantConfig(n)
});
const r = this.analyzeConfigChanges(i, o, n);
this.logger.info("Configuration change analysis completed", {
traceId: t
}, r);
try {
if (r.requiresRestart) return await this.handleRestartRequiredChanges(n, t); else if (r.canApplyRuntime) return await this.handleRuntimeChanges(r, e, n, t);
return !0;
} catch (e) {
this.logger.error("Configuration update failed", {
traceId: t
}, e);
return !1;
}
}
async gracefulShutdown(e = {}) {
if (this.shutdownManager.isInShutdown()) {
this.logger.warn("Graceful shutdown already in progress");
throw new Error("Graceful shutdown already in progress");
}
const t = [ ShutdownStepFactory.createStopAcceptingStep((e => this.stopAcceptingNewConnections(e)), e.stepTimeout || 5e3), ShutdownStepFactory.createWaitConnectionsStep(((e, t) => this.waitForConnectionCompletion(e, t)), e.stepTimeout || 15e3), ShutdownStepFactory.createForceCloseStep((e => this.forceCloseRemainingConnections(e)), e.stepTimeout || 5e3), ShutdownStepFactory.createStopMonitoringStep((e => this.stopMonitoringAndCleanup(e)), 3e3) ];
const o = await this.shutdownManager.performGracefulShutdown(t, e);
if (o.status === "failed") this.logger.error("Graceful shutdown failed", {}, {
failedSteps: o.failedSteps.map((e => e.step)),
totalTime: o.totalTime
});
return o;
}
detectConfigurationChanges(e, t) {
return Object.keys(t).filter((o => !f(e[o], t[o])));
}
setupConnectionPoolEventListeners() {
if (!this.connectionPool) return;
this.connectionPool.on(T.POOL_LIMIT_REACHED, (e => {
this.logger.warn(`${this.protocol.toUpperCase()} connection pool limit reached`, {}, e);
}));
this.connectionPool.on(T.HEALTH_STATUS_CHANGED, (e => {
this.logger.info(`${this.protocol.toUpperCase()} connection pool health status changed`, {}, e);
}));
this.connectionPool.on(T.CONNECTION_ERROR, (e => {
var t;
this.logger.warn(`${this.protocol.toUpperCase()} connection pool error`, {}, {
error: (t = e.error) === null || t === void 0 ? void 0 : t.message,
connectionId: e.connectionId
});
}));
this.connectionPool.on(T.CONNECTION_TIMEOUT, (e => {
this.logger.warn(`${this.protocol.toUpperCase()} connection timeout`, {}, e);
}));
this.connectionPool.on(T.CONNECTION_REMOVED, (e => {
this.logger.debug(`${this.protocol.toUpperCase()} connection removed from pool`, {}, {
connectionId: e.connectionId,
reason: e.reason
});
}));
}
setupPeriodicCleanup() {
if (!this.connectionPool) return;
this.timerManager.addTimer("base_cleanup", (() => {
const e = this.connectionPool.getMetrics();
if (e.activeConnections === 0 && e.totalConnections > 0) this.logger.deb