mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 12:15:57 +00:00
fix(cliproxy): prevent OAuth process hang on Qwen device code flow
- Escalate SIGTERM to SIGKILL after 3s if Go binary is stuck in blocking HTTP call - Extend timeout to 300s for device code flows matching CLIProxy binary polling window - Apply SIGKILL escalation to both SIGINT cleanup and timeout handlers Closes #314
This commit is contained in:
@@ -6,6 +6,19 @@
|
||||
*/
|
||||
|
||||
import { spawn, ChildProcess } from 'child_process';
|
||||
|
||||
/**
|
||||
* Kill process with SIGTERM, escalating to SIGKILL if it doesn't exit
|
||||
*/
|
||||
function killWithEscalation(proc: ChildProcess, gracePeriodMs = 3000): void {
|
||||
proc.kill('SIGTERM');
|
||||
const timer = setTimeout(() => {
|
||||
if (proc.exitCode === null) {
|
||||
proc.kill('SIGKILL');
|
||||
}
|
||||
}, gracePeriodMs);
|
||||
proc.once('exit', () => clearTimeout(timer));
|
||||
}
|
||||
import { ok, fail, info, warn } from '../../utils/ui';
|
||||
import { tryKiroImport } from './kiro-import';
|
||||
import { CLIProxyProvider } from '../types';
|
||||
@@ -333,8 +346,8 @@ export function executeOAuthProcess(options: OAuthProcessOptions): Promise<Accou
|
||||
// H8: Also clear stdinKeepalive interval to prevent memory leak
|
||||
const cleanup = () => {
|
||||
if (stdinKeepalive) clearInterval(stdinKeepalive);
|
||||
if (authProcess && !authProcess.killed) {
|
||||
authProcess.kill('SIGTERM');
|
||||
if (authProcess && authProcess.exitCode === null) {
|
||||
killWithEscalation(authProcess);
|
||||
}
|
||||
};
|
||||
process.on('SIGINT', cleanup);
|
||||
@@ -425,7 +438,8 @@ export function executeOAuthProcess(options: OAuthProcessOptions): Promise<Accou
|
||||
}, 2000);
|
||||
|
||||
// Timeout handling
|
||||
const timeoutMs = headless ? 300000 : 120000;
|
||||
// Device code flows need longer timeout to match CLIProxy binary's polling window (60 attempts × 5s = 300s)
|
||||
const timeoutMs = headless || isDeviceCodeFlow ? 300000 : 120000;
|
||||
const timeout = setTimeout(() => {
|
||||
// H7: Clear stdin keepalive interval
|
||||
if (stdinKeepalive) clearInterval(stdinKeepalive);
|
||||
@@ -435,9 +449,9 @@ export function executeOAuthProcess(options: OAuthProcessOptions): Promise<Accou
|
||||
authSessionEvents.removeListener('session:cancelled', handleCancel);
|
||||
unregisterAuthSession(state.sessionId);
|
||||
cancelProjectSelection(state.sessionId);
|
||||
authProcess.kill();
|
||||
killWithEscalation(authProcess);
|
||||
console.log('');
|
||||
console.log(fail(`OAuth timed out after ${headless ? 5 : 2} minutes`));
|
||||
console.log(fail(`OAuth timed out after ${timeoutMs / 60000} minutes`));
|
||||
for (const line of getTimeoutTroubleshooting(provider, callbackPort ?? null)) {
|
||||
console.log(line);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user