mcp-log-query-server 3.5.2 → 3.6.0
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/index.js +62 -19
- package/loki-client.js +506 -483
- package/package.json +1 -1
- package/ssh-client.js +56 -6
package/package.json
CHANGED
package/ssh-client.js
CHANGED
|
@@ -35,9 +35,13 @@ const _sshSem = {
|
|
|
35
35
|
/**
|
|
36
36
|
* 获取 SSH 信号量槽位
|
|
37
37
|
* @param {number} [timeoutMs] - 排队超时(默认 60s),防止无限等
|
|
38
|
+
* @param {AbortSignal} [signal] - 用户 cancel 信号,abort 时立即从队列移除并 reject
|
|
38
39
|
* @returns {Promise<void>}
|
|
39
40
|
*/
|
|
40
|
-
function sshAcquire(timeoutMs = SSH_ACQUIRE_TIMEOUT) {
|
|
41
|
+
function sshAcquire(timeoutMs = SSH_ACQUIRE_TIMEOUT, signal) {
|
|
42
|
+
if (signal && signal.aborted) {
|
|
43
|
+
return Promise.reject(new Error('CANCELLED before SSH acquire'));
|
|
44
|
+
}
|
|
41
45
|
if (_sshSem.active < _sshSem.max) {
|
|
42
46
|
_sshSem.active++;
|
|
43
47
|
log(`[SSH-Sem] acquire 直接通过 (active=${_sshSem.active}/${_sshSem.max}, queue=${_sshSem.queue.length})`);
|
|
@@ -49,10 +53,15 @@ function sshAcquire(timeoutMs = SSH_ACQUIRE_TIMEOUT) {
|
|
|
49
53
|
log(`[SSH-Sem] acquire 进入排队 (active=${_sshSem.active}/${_sshSem.max}, queue=${_sshSem.queue.length + 1}, timeout=${timeoutMs}ms)`);
|
|
50
54
|
return new Promise((resolve, reject) => {
|
|
51
55
|
let settled = false;
|
|
56
|
+
let onAbort;
|
|
57
|
+
const cleanup = () => {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
if (signal && onAbort) signal.removeEventListener('abort', onAbort);
|
|
60
|
+
};
|
|
52
61
|
const enterQueue = () => {
|
|
53
|
-
if (settled) return; //
|
|
62
|
+
if (settled) return; // 已超时/已取消,放弃并立刻腾位给下一个
|
|
54
63
|
settled = true;
|
|
55
|
-
|
|
64
|
+
cleanup();
|
|
56
65
|
_sshSem.active++;
|
|
57
66
|
log(`[SSH-Sem] acquire 出队获得槽位 (active=${_sshSem.active}/${_sshSem.max}, queue=${_sshSem.queue.length})`);
|
|
58
67
|
resolve();
|
|
@@ -61,12 +70,23 @@ function sshAcquire(timeoutMs = SSH_ACQUIRE_TIMEOUT) {
|
|
|
61
70
|
const timer = setTimeout(() => {
|
|
62
71
|
if (settled) return;
|
|
63
72
|
settled = true;
|
|
64
|
-
|
|
73
|
+
cleanup();
|
|
65
74
|
const idx = _sshSem.queue.indexOf(enterQueue);
|
|
66
75
|
if (idx >= 0) _sshSem.queue.splice(idx, 1);
|
|
67
76
|
log(`[SSH-Sem] acquire 排队超时 (${timeoutMs}ms, active=${_sshSem.active}/${_sshSem.max}, queue=${_sshSem.queue.length})`);
|
|
68
77
|
reject(new Error(`SSH 排队等待超时 (${timeoutMs}ms):前面请求卡住,或并发过高。可调整 SSH_MAX_CONCURRENT / SSH_ACQUIRE_TIMEOUT`));
|
|
69
78
|
}, timeoutMs);
|
|
79
|
+
// 用户 cancel:立即从队列移除
|
|
80
|
+
onAbort = () => {
|
|
81
|
+
if (settled) return;
|
|
82
|
+
settled = true;
|
|
83
|
+
cleanup();
|
|
84
|
+
const idx = _sshSem.queue.indexOf(enterQueue);
|
|
85
|
+
if (idx >= 0) _sshSem.queue.splice(idx, 1);
|
|
86
|
+
log(`[SSH-Sem] acquire 用户 cancel,从队列移除 (active=${_sshSem.active}/${_sshSem.max}, queue=${_sshSem.queue.length})`);
|
|
87
|
+
reject(new Error('CANCELLED in SSH queue'));
|
|
88
|
+
};
|
|
89
|
+
if (signal) signal.addEventListener('abort', onAbort, { once: true });
|
|
70
90
|
});
|
|
71
91
|
}
|
|
72
92
|
|
|
@@ -87,8 +107,9 @@ function sshRelease() {
|
|
|
87
107
|
*/
|
|
88
108
|
export async function queryLog(service, command, options = {}) {
|
|
89
109
|
const timeout = options.timeout || DEFAULTS.timeout;
|
|
110
|
+
const signal = options.signal;
|
|
90
111
|
|
|
91
|
-
await sshAcquire();
|
|
112
|
+
await sshAcquire(undefined, signal);
|
|
92
113
|
try {
|
|
93
114
|
return await new Promise((resolve, reject) => {
|
|
94
115
|
const conn = new Client();
|
|
@@ -108,6 +129,20 @@ export async function queryLog(service, command, options = {}) {
|
|
|
108
129
|
}
|
|
109
130
|
}, timeout);
|
|
110
131
|
|
|
132
|
+
// 用户 cancel:立即 destroy 连接
|
|
133
|
+
const onAbort = () => {
|
|
134
|
+
if (settled) return;
|
|
135
|
+
settled = true;
|
|
136
|
+
clearTimeout(timeoutId);
|
|
137
|
+
log(`[SSH] ⊗ 用户 cancel,destroy 连接 (${service.name})`);
|
|
138
|
+
try { conn.destroy(); } catch {};
|
|
139
|
+
reject(new Error('CANCELLED during SSH'));
|
|
140
|
+
};
|
|
141
|
+
if (signal) {
|
|
142
|
+
if (signal.aborted) { onAbort(); return; }
|
|
143
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
144
|
+
}
|
|
145
|
+
|
|
111
146
|
conn.on('ready', () => {
|
|
112
147
|
conn.shell({ term: 'xterm', rows: 24, cols: 500 }, (err, stream) => {
|
|
113
148
|
if (err) {
|
|
@@ -267,8 +302,9 @@ export async function testConnection() {
|
|
|
267
302
|
*/
|
|
268
303
|
export async function executeKubectl(kubectlCommand, options = {}) {
|
|
269
304
|
const timeout = options.timeout || DEFAULTS.timeout;
|
|
305
|
+
const signal = options.signal;
|
|
270
306
|
|
|
271
|
-
await sshAcquire();
|
|
307
|
+
await sshAcquire(undefined, signal);
|
|
272
308
|
try {
|
|
273
309
|
return await new Promise((resolve, reject) => {
|
|
274
310
|
const conn = new Client();
|
|
@@ -288,6 +324,20 @@ export async function executeKubectl(kubectlCommand, options = {}) {
|
|
|
288
324
|
}
|
|
289
325
|
}, timeout);
|
|
290
326
|
|
|
327
|
+
// 用户 cancel:立即 destroy 连接
|
|
328
|
+
const onAbort = () => {
|
|
329
|
+
if (settled) return;
|
|
330
|
+
settled = true;
|
|
331
|
+
clearTimeout(timeoutId);
|
|
332
|
+
log(`[SSH] ⊗ 用户 cancel,destroy 连接 (kubectl: ${kubectlCommand.substring(0, 50)}...)`);
|
|
333
|
+
try { conn.destroy(); } catch {};
|
|
334
|
+
reject(new Error('CANCELLED during kubectl'));
|
|
335
|
+
};
|
|
336
|
+
if (signal) {
|
|
337
|
+
if (signal.aborted) { onAbort(); return; }
|
|
338
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
339
|
+
}
|
|
340
|
+
|
|
291
341
|
conn.on('ready', () => {
|
|
292
342
|
conn.shell({ term: 'xterm', rows: 24, cols: 500 }, (err, stream) => {
|
|
293
343
|
if (err) {
|