fix: 修复设计 Agent 慢响应超时
问题:客户端每 250ms 轮询 Run,并在 120 秒固定超时,导致服务端日志刷屏且慢响应被提前判定失败。 修复:将轮询改为 1 秒起步、最高 5 秒的指数退避,并将等待窗口调整为 10 分钟;新增 150 秒慢 Run 回归测试。
This commit is contained in:
@@ -190,8 +190,9 @@ type TaskEventQueue = {
|
||||
|
||||
const AGENT_WEBSOCKET_OPEN = 1;
|
||||
const AGENT_WEBSOCKET_PING_INTERVAL_MS = 20_000;
|
||||
const AGENT_RUN_POLL_INTERVAL_MS = 250;
|
||||
const AGENT_RUN_TIMEOUT_MS = 120_000;
|
||||
const AGENT_RUN_INITIAL_POLL_INTERVAL_MS = 1_000;
|
||||
const AGENT_RUN_MAX_POLL_INTERVAL_MS = 5_000;
|
||||
const AGENT_RUN_TIMEOUT_MS = 10 * 60_000;
|
||||
|
||||
function mapBrief(brief: ServerBrief): DesignBrief {
|
||||
return {
|
||||
@@ -737,6 +738,7 @@ export class WorksSquareDesignWorkspace implements DesignWorkspaceModule {
|
||||
|
||||
private async waitForAgentRun(sessionId: string, runId: string): Promise<ServerAgentRun> {
|
||||
const deadline = Date.now() + AGENT_RUN_TIMEOUT_MS;
|
||||
let pollInterval = AGENT_RUN_INITIAL_POLL_INTERVAL_MS;
|
||||
while (true) {
|
||||
const run = await this.requestJson<ServerAgentRun>(
|
||||
`/api/agents/sessions/${encodeURIComponent(sessionId)}/runs/${encodeURIComponent(runId)}`,
|
||||
@@ -751,7 +753,8 @@ export class WorksSquareDesignWorkspace implements DesignWorkspaceModule {
|
||||
'设计 Agent 响应超时,请稍后重试',
|
||||
);
|
||||
}
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, AGENT_RUN_POLL_INTERVAL_MS));
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, pollInterval));
|
||||
pollInterval = Math.min(pollInterval * 2, AGENT_RUN_MAX_POLL_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +210,59 @@ describe('Works Square AI design adapter', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('waits for a slow design run without flooding the run endpoint', async () => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date('2026-08-03T02:00:00Z'));
|
||||
const startedAt = Date.now();
|
||||
let runPolls = 0;
|
||||
const fetchMock = vi.fn<typeof fetch>(async (input, init) => {
|
||||
const url = String(input);
|
||||
if (url.endsWith('/api/agents/sessions')) {
|
||||
return jsonResponse({ session_id: 'session-slow', status: 'active' }, 201);
|
||||
}
|
||||
if (url.endsWith('/api/agents/sessions/session-slow/commands')) {
|
||||
return jsonResponse({ run_id: 'run-slow', status: 'queued', error: null }, 202);
|
||||
}
|
||||
if (url.endsWith('/api/agents/sessions/session-slow/runs/run-slow')) {
|
||||
runPolls += 1;
|
||||
return jsonResponse({
|
||||
run_id: 'run-slow',
|
||||
status: Date.now() - startedAt >= 150_000 ? 'succeeded' : 'running',
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
if (url.endsWith('/api/design/workspaces/workspace-one')) {
|
||||
return jsonResponse(serverWorkspace);
|
||||
}
|
||||
throw new Error(`Unexpected request: ${url} ${init?.method ?? 'GET'}`);
|
||||
});
|
||||
const adapter = new WorksSquareDesignWorkspace({
|
||||
apiBaseUrl: 'https://square.example',
|
||||
fetchImpl: fetchMock,
|
||||
});
|
||||
|
||||
try {
|
||||
const outcomePromise = adapter.submitMessage({
|
||||
workspaceId: 'workspace-one',
|
||||
clientTurnId: 'turn-slow',
|
||||
expectedTurnRevision: 1,
|
||||
message: '整理一个复杂的品牌设计方向',
|
||||
}).then(
|
||||
(value) => ({ value, error: null }),
|
||||
(error: unknown) => ({ value: null, error }),
|
||||
);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(160_000);
|
||||
const outcome = await outcomePromise;
|
||||
|
||||
expect(outcome.error).toBeNull();
|
||||
expect(outcome.value).toMatchObject({ workspaceId: 'workspace-one' });
|
||||
expect(runPolls).toBeLessThanOrEqual(40);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it('maps an invalid Runtime command to a user input error', async () => {
|
||||
const fetchMock = vi.fn<typeof fetch>()
|
||||
.mockResolvedValueOnce(jsonResponse({
|
||||
|
||||
Reference in New Issue
Block a user