mirror of
https://github.com/cnlimiter/codex-register.git
synced 2026-06-08 17:10:05 +08:00
fix: route batch websocket fallback by task type
This commit is contained in:
@@ -1306,7 +1306,7 @@ function connectBatchWebSocket(batchId) {
|
|||||||
|
|
||||||
if (shouldPoll && currentBatch) {
|
if (shouldPoll && currentBatch) {
|
||||||
console.log('切换到轮询模式');
|
console.log('切换到轮询模式');
|
||||||
startOutlookBatchPolling(currentBatch.batch_id);
|
startCurrentBatchPolling(currentBatch.batch_id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1314,12 +1314,12 @@ function connectBatchWebSocket(batchId) {
|
|||||||
console.error('批量任务 WebSocket 错误:', error);
|
console.error('批量任务 WebSocket 错误:', error);
|
||||||
stopBatchWebSocketHeartbeat();
|
stopBatchWebSocketHeartbeat();
|
||||||
// 切换到轮询
|
// 切换到轮询
|
||||||
startOutlookBatchPolling(batchId);
|
startCurrentBatchPolling(batchId);
|
||||||
};
|
};
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('批量任务 WebSocket 连接失败:', error);
|
console.error('批量任务 WebSocket 连接失败:', error);
|
||||||
startOutlookBatchPolling(batchId);
|
startCurrentBatchPolling(batchId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1332,6 +1332,15 @@ function disconnectBatchWebSocket() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startCurrentBatchPolling(batchId) {
|
||||||
|
if (isOutlookBatchMode) {
|
||||||
|
startOutlookBatchPolling(batchId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startBatchPolling(batchId);
|
||||||
|
}
|
||||||
|
|
||||||
// 开始批量任务心跳
|
// 开始批量任务心跳
|
||||||
function startBatchWebSocketHeartbeat() {
|
function startBatchWebSocketHeartbeat() {
|
||||||
stopBatchWebSocketHeartbeat();
|
stopBatchWebSocketHeartbeat();
|
||||||
|
|||||||
133
tests/test_batch_websocket_fallback.cjs
Normal file
133
tests/test_batch_websocket_fallback.cjs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const vm = require('node:vm');
|
||||||
|
|
||||||
|
const APP_JS_PATH = '/Users/zhoukailian/.config/superpowers/worktrees/codex-manager/repro-batch-monitor/static/js/app.js';
|
||||||
|
|
||||||
|
function createElementStub() {
|
||||||
|
return {
|
||||||
|
style: {},
|
||||||
|
dataset: {},
|
||||||
|
value: '',
|
||||||
|
checked: false,
|
||||||
|
disabled: false,
|
||||||
|
innerHTML: '',
|
||||||
|
textContent: '',
|
||||||
|
className: '',
|
||||||
|
appendChild() {},
|
||||||
|
addEventListener() {},
|
||||||
|
removeEventListener() {},
|
||||||
|
querySelector() {
|
||||||
|
return createElementStub();
|
||||||
|
},
|
||||||
|
querySelectorAll() {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
closest() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSandbox() {
|
||||||
|
const sandbox = {
|
||||||
|
console,
|
||||||
|
setTimeout,
|
||||||
|
clearTimeout,
|
||||||
|
setInterval: () => 1,
|
||||||
|
clearInterval: () => {},
|
||||||
|
Event: class Event {
|
||||||
|
constructor(type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
document: {
|
||||||
|
getElementById() {
|
||||||
|
return createElementStub();
|
||||||
|
},
|
||||||
|
createElement() {
|
||||||
|
return createElementStub();
|
||||||
|
},
|
||||||
|
addEventListener() {},
|
||||||
|
querySelector() {
|
||||||
|
return createElementStub();
|
||||||
|
},
|
||||||
|
querySelectorAll() {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sessionStorage: {
|
||||||
|
getItem() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
setItem() {},
|
||||||
|
removeItem() {},
|
||||||
|
},
|
||||||
|
toast: {
|
||||||
|
info() {},
|
||||||
|
success() {},
|
||||||
|
warning() {},
|
||||||
|
error() {},
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
get() {
|
||||||
|
throw new Error('api.get should not be called in this test');
|
||||||
|
},
|
||||||
|
post() {
|
||||||
|
throw new Error('api.post should not be called in this test');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
window: null,
|
||||||
|
WebSocket: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
sandbox.window = sandbox;
|
||||||
|
sandbox.window.location = { protocol: 'http:', host: '127.0.0.1:8003' };
|
||||||
|
|
||||||
|
vm.createContext(sandbox);
|
||||||
|
vm.runInContext(fs.readFileSync(APP_JS_PATH, 'utf8'), sandbox, { filename: 'app.js' });
|
||||||
|
|
||||||
|
return sandbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runFallback(mode) {
|
||||||
|
const sandbox = createSandbox();
|
||||||
|
|
||||||
|
vm.runInContext(
|
||||||
|
`
|
||||||
|
var __calls = [];
|
||||||
|
currentBatch = { batch_id: 'test-batch' };
|
||||||
|
isOutlookBatchMode = ${mode === 'outlook' ? 'true' : 'false'};
|
||||||
|
batchCompleted = false;
|
||||||
|
batchFinalStatus = null;
|
||||||
|
startOutlookBatchPolling = function(batchId) { __calls.push(['outlook', batchId]); };
|
||||||
|
startBatchPolling = function(batchId) { __calls.push(['batch', batchId]); };
|
||||||
|
WebSocket = function(url) {
|
||||||
|
this.url = url;
|
||||||
|
this.readyState = 0;
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.onerror) {
|
||||||
|
this.onerror({ type: 'error' });
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
WebSocket.OPEN = 1;
|
||||||
|
connectBatchWebSocket('test-batch');
|
||||||
|
`,
|
||||||
|
sandbox,
|
||||||
|
);
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 20));
|
||||||
|
return JSON.parse(vm.runInContext('JSON.stringify(__calls)', sandbox));
|
||||||
|
}
|
||||||
|
|
||||||
|
test('normal batch websocket fallback uses standard batch polling', async () => {
|
||||||
|
const calls = await runFallback('batch');
|
||||||
|
assert.deepEqual(calls, [['batch', 'test-batch']]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('outlook batch websocket fallback uses outlook polling', async () => {
|
||||||
|
const calls = await runFallback('outlook');
|
||||||
|
assert.deepEqual(calls, [['outlook', 'test-batch']]);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user