@be-link/ecommerce-trade-service-node-sdk 0.1.52 → 0.1.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/modules/pos/orderQuery/types.d.ts +2 -2
- package/package.json +4 -3
- package/utils/http.d.ts +0 -24
- package/utils/http.js +74 -245
|
@@ -167,8 +167,7 @@ export declare namespace PosOrderQueryService {
|
|
|
167
167
|
/** 商品ID */
|
|
168
168
|
productId: string;
|
|
169
169
|
}
|
|
170
|
-
|
|
171
|
-
}
|
|
170
|
+
type IExportOrderData = IOrderList;
|
|
172
171
|
interface IExportOrderDataByIds {
|
|
173
172
|
/** 订单IDs */
|
|
174
173
|
orderIds: string[];
|
|
@@ -182,6 +181,7 @@ export declare namespace PosOrderQueryService {
|
|
|
182
181
|
createdAt: number;
|
|
183
182
|
/** 支付时间 */
|
|
184
183
|
payTime?: number;
|
|
184
|
+
userId: string;
|
|
185
185
|
source: ENUM.OrderSource;
|
|
186
186
|
platform: ENUM.OrderPlatform;
|
|
187
187
|
productId: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@be-link/ecommerce-trade-service-node-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
4
4
|
"description": "EcommerceTradeService Node.js SDK",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
"@fastify/request-context": "6.2.1",
|
|
14
14
|
"axios": "1.13.2",
|
|
15
15
|
"axios-retry": "4.0.0",
|
|
16
|
-
"
|
|
17
|
-
"tsoa": "^6.6.0"
|
|
16
|
+
"safe-stable-stringify": "^2.5.0",
|
|
17
|
+
"tsoa": "^6.6.0",
|
|
18
|
+
"uuid": "9.0.1"
|
|
18
19
|
},
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "rm -rf ./dist && tsc && cp package.json README.md ./dist/ 2>/dev/null || true",
|
package/utils/http.d.ts
CHANGED
|
@@ -9,27 +9,3 @@ declare module '@fastify/request-context' {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
export declare function callApi<T extends (...args: any[]) => Promise<any>>(url: string, request?: Parameters<T>[0]): Promise<Awaited<ReturnType<T>>>;
|
|
12
|
-
export declare function getConnectionStats(): {
|
|
13
|
-
activeRequests: number;
|
|
14
|
-
totalRequests: number;
|
|
15
|
-
peakActiveRequests: number;
|
|
16
|
-
httpSockets: {
|
|
17
|
-
total: number;
|
|
18
|
-
hosts: number;
|
|
19
|
-
details: NodeJS.ReadOnlyDict<import("net").Socket[]>;
|
|
20
|
-
};
|
|
21
|
-
httpsSockets: {
|
|
22
|
-
total: number;
|
|
23
|
-
hosts: number;
|
|
24
|
-
details: NodeJS.ReadOnlyDict<import("net").Socket[]>;
|
|
25
|
-
};
|
|
26
|
-
config: {
|
|
27
|
-
maxSockets: number;
|
|
28
|
-
maxTotalSockets: number;
|
|
29
|
-
requestTimeout: number;
|
|
30
|
-
note: string;
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
export declare function resetPeakStats(): void;
|
|
34
|
-
export declare function startMonitoring(interval?: number): void;
|
|
35
|
-
export declare function stopMonitoring(): void;
|
package/utils/http.js
CHANGED
|
@@ -1,121 +1,68 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
39
|
exports.callApi = callApi;
|
|
7
|
-
exports.getConnectionStats = getConnectionStats;
|
|
8
|
-
exports.resetPeakStats = resetPeakStats;
|
|
9
|
-
exports.startMonitoring = startMonitoring;
|
|
10
|
-
exports.stopMonitoring = stopMonitoring;
|
|
11
|
-
const request_context_1 = require("@fastify/request-context");
|
|
12
40
|
const axios_1 = __importDefault(require("axios"));
|
|
13
|
-
const axios_retry_1 = __importDefault(require("axios-retry"));
|
|
14
|
-
const http_1 = __importDefault(require("http"));
|
|
15
|
-
const https_1 = __importDefault(require("https"));
|
|
16
41
|
const uuid_1 = require("uuid");
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
maxFreeSockets: 500, // 空闲socket保留数(提升复用率)
|
|
21
|
-
maxTotalSockets: 8000, // 所有主机总socket数(进一步提升)
|
|
22
|
-
keepAliveMsecs: 60000, // 保持连接60秒(减少重连)
|
|
23
|
-
timeout: 60000, // socket超时60秒(增加以防止长请求失败)
|
|
24
|
-
requestTimeout: 60000, // 请求超时60秒(适当放宽)
|
|
25
|
-
retries: 2, // 重试2次(提高成功率)
|
|
26
|
-
retryBaseDelay: 100, // 基础重试延迟100ms(给服务恢复时间)
|
|
27
|
-
logThreshold: 500, // 日志采样率(每500个请求采样1次)
|
|
28
|
-
monitorInterval: 5000, // 监控日志间隔(毫秒)
|
|
29
|
-
};
|
|
30
|
-
// 配置 HTTP/HTTPS Agent 以支持高并发连接池和 keepAlive
|
|
31
|
-
const httpAgent = new http_1.default.Agent({
|
|
32
|
-
keepAlive: true,
|
|
33
|
-
keepAliveMsecs: HTTP_CONFIG.keepAliveMsecs,
|
|
34
|
-
maxSockets: HTTP_CONFIG.maxSockets,
|
|
35
|
-
maxFreeSockets: HTTP_CONFIG.maxFreeSockets,
|
|
36
|
-
maxTotalSockets: HTTP_CONFIG.maxTotalSockets,
|
|
37
|
-
timeout: HTTP_CONFIG.timeout,
|
|
38
|
-
scheduling: 'fifo', // 先进先出调度
|
|
39
|
-
});
|
|
40
|
-
const httpsAgent = new https_1.default.Agent({
|
|
41
|
-
keepAlive: true,
|
|
42
|
-
keepAliveMsecs: HTTP_CONFIG.keepAliveMsecs,
|
|
43
|
-
maxSockets: HTTP_CONFIG.maxSockets,
|
|
44
|
-
maxFreeSockets: HTTP_CONFIG.maxFreeSockets,
|
|
45
|
-
maxTotalSockets: HTTP_CONFIG.maxTotalSockets,
|
|
46
|
-
timeout: HTTP_CONFIG.timeout,
|
|
47
|
-
scheduling: 'fifo',
|
|
48
|
-
});
|
|
49
|
-
// 配置 axios 默认使用这些 agent
|
|
50
|
-
axios_1.default.defaults.httpAgent = httpAgent;
|
|
51
|
-
axios_1.default.defaults.httpsAgent = httpsAgent;
|
|
52
|
-
axios_1.default.defaults.timeout = HTTP_CONFIG.requestTimeout;
|
|
53
|
-
axios_1.default.defaults.maxRedirects = 3; // 限制重定向次数
|
|
54
|
-
axios_1.default.defaults.maxContentLength = 50 * 1024 * 1024; // 50MB 最大响应大小
|
|
55
|
-
// 高并发场景下的智能重试配置
|
|
42
|
+
const axios_retry_1 = __importDefault(require("axios-retry"));
|
|
43
|
+
const request_context_1 = require("@fastify/request-context");
|
|
44
|
+
const safe_stable_stringify_1 = __importDefault(require("safe-stable-stringify"));
|
|
56
45
|
(0, axios_retry_1.default)(axios_1.default, {
|
|
57
|
-
retries:
|
|
46
|
+
retries: 1,
|
|
58
47
|
retryCondition(error) {
|
|
59
|
-
|
|
60
|
-
const status = error.response?.status;
|
|
61
|
-
const isNetworkError = error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT';
|
|
62
|
-
const isServerError = status === 502 || status === 503 || status === 504;
|
|
63
|
-
const isRateLimited = status === 429;
|
|
64
|
-
return isNetworkError || isServerError || isRateLimited;
|
|
48
|
+
return error.response?.status === 502;
|
|
65
49
|
},
|
|
66
|
-
retryDelay: (retryCount
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (retryAfter) {
|
|
73
|
-
return parseInt(retryAfter) * 1000;
|
|
74
|
-
}
|
|
75
|
-
return 1000 + Math.random() * 1000; // 1-2秒
|
|
76
|
-
}
|
|
77
|
-
// 指数退避:100ms, 200ms, 400ms...
|
|
78
|
-
const exponentialDelay = HTTP_CONFIG.retryBaseDelay * Math.pow(2, retryCount - 1);
|
|
79
|
-
const jitter = Math.random() * 50; // 0-50ms 抖动
|
|
80
|
-
return Math.min(exponentialDelay + jitter, 2000); // 最多延迟2秒
|
|
50
|
+
retryDelay: (retryCount) => {
|
|
51
|
+
console.info(`retryCount: ${retryCount}, retryDelay: ${retryCount * 500}`);
|
|
52
|
+
return retryCount * 500;
|
|
53
|
+
},
|
|
54
|
+
onRetry(retryCount, error, requestConfig) {
|
|
55
|
+
console.info(`retryCount: ${retryCount}, onRetry: ${error.message}, requestHeader: ${(0, safe_stable_stringify_1.default)(requestConfig.headers)}`);
|
|
81
56
|
},
|
|
82
|
-
shouldResetTimeout: true, // 重试时重置超时
|
|
83
57
|
});
|
|
84
|
-
// 连接池状态监控
|
|
85
|
-
let requestCount = 0;
|
|
86
|
-
let activeRequests = 0;
|
|
87
|
-
let peakActiveRequests = 0; // 峰值并发
|
|
88
|
-
// 注意:已移除应用层并发队列限制,完全依赖底层socket连接池控制
|
|
89
|
-
// 这样可以避免应用层排队等待,充分利用socket连接池的并发能力
|
|
90
58
|
async function callApi(url, request) {
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
peakActiveRequests = activeRequests;
|
|
97
|
-
}
|
|
98
|
-
// 批量获取请求上下文,减少函数调用开销
|
|
99
|
-
const ctx = request_context_1.requestContext.get('requestId') ? request_context_1.requestContext : null;
|
|
100
|
-
const requestId = ctx?.get('requestId') || ctx?.get('traceMessageId') || (0, uuid_1.v4)();
|
|
101
|
-
const pandoraUserId = ctx?.get('pandoraUserId') || '';
|
|
102
|
-
const beLinkUserId = ctx?.get('beLinkUserId') || '';
|
|
103
|
-
const pandoraRoleId = ctx?.get('pandoraRoleId') || '';
|
|
104
|
-
const realIp = ctx?.get('realIp') || '';
|
|
105
|
-
// 采样日志决策(提前计算,避免重复判断)
|
|
106
|
-
const shouldLog = currentRequestId % HTTP_CONFIG.logThreshold === 0;
|
|
107
|
-
const startTime = shouldLog ? Date.now() : 0;
|
|
59
|
+
const requestId = request_context_1.requestContext.get('requestId') || request_context_1.requestContext.get('traceMessageId') || (0, uuid_1.v4)();
|
|
60
|
+
const pandoraUserId = request_context_1.requestContext.get('pandoraUserId') || '';
|
|
61
|
+
const beLinkUserId = request_context_1.requestContext.get('beLinkUserId') || '';
|
|
62
|
+
const pandoraRoleId = request_context_1.requestContext.get('pandoraRoleId') || '';
|
|
63
|
+
const realIp = request_context_1.requestContext.get('realIp') || '';
|
|
108
64
|
try {
|
|
109
|
-
|
|
110
|
-
console.log(JSON.stringify({
|
|
111
|
-
message: '发起HTTP请求',
|
|
112
|
-
currentRequestId,
|
|
113
|
-
activeRequests,
|
|
114
|
-
requestId,
|
|
115
|
-
url,
|
|
116
|
-
type: 'http_request_start',
|
|
117
|
-
}));
|
|
118
|
-
}
|
|
65
|
+
console.info(`准备发起ecommerce-trade-service请求[${requestId}]: ${url}, 参数: ${(0, safe_stable_stringify_1.default)(request)}`);
|
|
119
66
|
const response = await axios_1.default.post(url, request, {
|
|
120
67
|
headers: {
|
|
121
68
|
'x-request-id': requestId,
|
|
@@ -123,160 +70,42 @@ async function callApi(url, request) {
|
|
|
123
70
|
'x-belink-userid': beLinkUserId,
|
|
124
71
|
'x-belink-pandora-roleid': pandoraRoleId,
|
|
125
72
|
'x-real-ip': realIp,
|
|
126
|
-
Connection: 'keep-alive',
|
|
127
73
|
},
|
|
128
|
-
timeout: HTTP_CONFIG.requestTimeout,
|
|
129
|
-
httpAgent,
|
|
130
|
-
httpsAgent,
|
|
131
74
|
});
|
|
132
|
-
if (shouldLog) {
|
|
133
|
-
const duration = Date.now() - startTime;
|
|
134
|
-
if (duration > 3000) {
|
|
135
|
-
console.log(JSON.stringify({
|
|
136
|
-
message: '请求完成',
|
|
137
|
-
currentRequestId,
|
|
138
|
-
duration: `${duration}ms`,
|
|
139
|
-
activeRequests,
|
|
140
|
-
type: 'http_request_complete',
|
|
141
|
-
}));
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
75
|
const responseData = response.data;
|
|
145
76
|
return responseData.data;
|
|
146
77
|
}
|
|
147
78
|
catch (error) {
|
|
148
79
|
const axiosError = error;
|
|
149
|
-
const duration = startTime ? Date.now() - startTime : 0;
|
|
150
|
-
// 错误始终记录(但简化输出)
|
|
151
|
-
console.error(JSON.stringify({
|
|
152
|
-
message: '请求失败',
|
|
153
|
-
currentRequestId,
|
|
154
|
-
url,
|
|
155
|
-
duration: `${duration}ms`,
|
|
156
|
-
activeRequests,
|
|
157
|
-
errorMessage: axiosError.message,
|
|
158
|
-
type: 'http_request_failed',
|
|
159
|
-
}));
|
|
160
80
|
if (axiosError.response) {
|
|
161
81
|
const response = axiosError.response;
|
|
162
82
|
const data = response.data;
|
|
163
|
-
console.error(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}));
|
|
169
|
-
}
|
|
170
|
-
throw error;
|
|
171
|
-
}
|
|
172
|
-
finally {
|
|
173
|
-
// 记录请求完成,减少活跃计数
|
|
174
|
-
activeRequests--;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
// 导出监控函数
|
|
178
|
-
function getConnectionStats() {
|
|
179
|
-
const stats = {
|
|
180
|
-
// 当前状态
|
|
181
|
-
activeRequests,
|
|
182
|
-
totalRequests: requestCount,
|
|
183
|
-
// 峰值指标
|
|
184
|
-
peakActiveRequests,
|
|
185
|
-
// Socket连接池状态(这是真正的并发控制点)
|
|
186
|
-
httpSockets: {
|
|
187
|
-
total: Object.keys(httpAgent.sockets).reduce((sum, host) => sum + (httpAgent.sockets[host]?.length || 0), 0),
|
|
188
|
-
hosts: Object.keys(httpAgent.sockets).length,
|
|
189
|
-
details: httpAgent.sockets,
|
|
190
|
-
},
|
|
191
|
-
httpsSockets: {
|
|
192
|
-
total: Object.keys(httpsAgent.sockets).reduce((sum, host) => sum + (httpsAgent.sockets[host]?.length || 0), 0),
|
|
193
|
-
hosts: Object.keys(httpsAgent.sockets).length,
|
|
194
|
-
details: httpsAgent.sockets,
|
|
195
|
-
},
|
|
196
|
-
// 配置信息
|
|
197
|
-
config: {
|
|
198
|
-
maxSockets: HTTP_CONFIG.maxSockets,
|
|
199
|
-
maxTotalSockets: HTTP_CONFIG.maxTotalSockets,
|
|
200
|
-
requestTimeout: HTTP_CONFIG.requestTimeout,
|
|
201
|
-
note: '已移除应用层并发队列限制,完全依赖socket连接池',
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
return stats;
|
|
205
|
-
}
|
|
206
|
-
// 重置峰值统计(可用于定期重置)
|
|
207
|
-
function resetPeakStats() {
|
|
208
|
-
peakActiveRequests = activeRequests;
|
|
209
|
-
console.log(JSON.stringify({
|
|
210
|
-
message: '峰值统计已重置',
|
|
211
|
-
type: 'stats_reset',
|
|
212
|
-
}));
|
|
213
|
-
}
|
|
214
|
-
// 定期监控日志
|
|
215
|
-
let monitorTimer = null;
|
|
216
|
-
function startMonitoring(interval = HTTP_CONFIG.monitorInterval) {
|
|
217
|
-
if (monitorTimer) {
|
|
218
|
-
console.log(JSON.stringify({
|
|
219
|
-
message: '监控已在运行中',
|
|
220
|
-
type: 'monitor_already_running',
|
|
221
|
-
}));
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
console.log(JSON.stringify({
|
|
225
|
-
message: '启动并发监控',
|
|
226
|
-
interval: `${interval}ms`,
|
|
227
|
-
type: 'monitor_start',
|
|
228
|
-
}));
|
|
229
|
-
monitorTimer = setInterval(() => {
|
|
230
|
-
const stats = getConnectionStats();
|
|
231
|
-
// 只在有活动时打印
|
|
232
|
-
if (stats.totalRequests === 0) {
|
|
233
|
-
return;
|
|
83
|
+
console.error(`ecommerce-trade-service 异常: ${axiosError.message},requestId: ${requestId}`);
|
|
84
|
+
console.info('响应信息', data.message);
|
|
85
|
+
console.error('异常堆栈', (0, safe_stable_stringify_1.default)(error.stack));
|
|
86
|
+
// throw new Error(data.errorType + ' - ' + data.message)
|
|
87
|
+
throw error;
|
|
234
88
|
}
|
|
235
|
-
//
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
type: 'monitor_bottleneck_detected',
|
|
251
|
-
}));
|
|
89
|
+
// 调用dns模块解析url
|
|
90
|
+
const dns = await Promise.resolve().then(() => __importStar(require('dns')));
|
|
91
|
+
const dnsPromise = new Promise((resolve, reject) => {
|
|
92
|
+
const lookupRes = dns.lookup(url, (err, address) => {
|
|
93
|
+
if (err) {
|
|
94
|
+
console.error(err.message);
|
|
95
|
+
reject(err);
|
|
96
|
+
}
|
|
97
|
+
console.info(`lookup: ${(0, safe_stable_stringify_1.default)(lookupRes)}`);
|
|
98
|
+
resolve(address);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
try {
|
|
102
|
+
const address = await dnsPromise;
|
|
103
|
+
console.info(`address: ${(0, safe_stable_stringify_1.default)(address)}`);
|
|
252
104
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
console.log(JSON.stringify({
|
|
256
|
-
message: '并发监控运行正常',
|
|
257
|
-
总请求: stats.totalRequests,
|
|
258
|
-
当前并发: stats.activeRequests,
|
|
259
|
-
峰值并发: stats.peakActiveRequests,
|
|
260
|
-
HTTP_Sockets使用率: `${Math.round(httpSocketsUsage * 100)}%`,
|
|
261
|
-
HTTPS_Sockets使用率: `${Math.round(httpsSocketsUsage * 100)}%`,
|
|
262
|
-
type: 'monitor_normal',
|
|
263
|
-
}));
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.info(`error: ${(0, safe_stable_stringify_1.default)(error)}`);
|
|
264
107
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
function stopMonitoring() {
|
|
268
|
-
if (monitorTimer) {
|
|
269
|
-
clearInterval(monitorTimer);
|
|
270
|
-
monitorTimer = null;
|
|
271
|
-
console.log(JSON.stringify({
|
|
272
|
-
message: '监控已停止',
|
|
273
|
-
type: 'monitor_stop',
|
|
274
|
-
}));
|
|
108
|
+
console.error(`ecommerce-trade-service 未知异常: ${axiosError.message}`, error.stack);
|
|
109
|
+
throw error;
|
|
275
110
|
}
|
|
276
111
|
}
|
|
277
|
-
// 自动启动监控(可选,如果不想自动启动可以注释掉)
|
|
278
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
279
|
-
setTimeout(() => {
|
|
280
|
-
startMonitoring();
|
|
281
|
-
}, 3000); // 延迟3秒启动,避免服务启动时的干扰
|
|
282
|
-
}
|