fix the issue of multiple calude using one server by claude code

This commit is contained in:
jinhui.li
2025-06-12 09:58:05 +08:00
parent c9059f146d
commit 84e76f24b0
5 changed files with 67 additions and 13 deletions

View File

@@ -43,10 +43,12 @@ async function waitForService(
return false; return false;
} }
import { spawn } from "child_process";
async function main() { async function main() {
switch (command) { switch (command) {
case "start": case "start":
await run({ daemon: true }); run();
break; break;
case "stop": case "stop":
await closeService(); await closeService();
@@ -57,8 +59,10 @@ async function main() {
case "code": case "code":
if (!isServiceRunning()) { if (!isServiceRunning()) {
console.log("Service not running, starting service..."); console.log("Service not running, starting service...");
await run({ daemon: true }); spawn("ccr", ["start"], {
// Wait for service to start, exit with error if timeout detached: true,
stdio: "ignore",
}).unref();
if (await waitForService()) { if (await waitForService()) {
executeCodeCommand(process.argv.slice(3)); executeCodeCommand(process.argv.slice(3));
} else { } else {

View File

@@ -6,8 +6,8 @@ import { formatRequest } from "./middlewares/formatRequest";
import { rewriteBody } from "./middlewares/rewriteBody"; import { rewriteBody } from "./middlewares/rewriteBody";
import OpenAI from "openai"; import OpenAI from "openai";
import { streamOpenAIResponse } from "./utils/stream"; import { streamOpenAIResponse } from "./utils/stream";
import { isServiceRunning, savePid } from "./utils/processCheck"; import { cleanupPidFile, isServiceRunning, savePid } from "./utils/processCheck";
import { fork } from "child_process";
async function initializeClaudeConfig() { async function initializeClaudeConfig() {
const homeDir = process.env.HOME; const homeDir = process.env.HOME;
@@ -31,7 +31,6 @@ async function initializeClaudeConfig() {
interface RunOptions { interface RunOptions {
port?: number; port?: number;
daemon?: boolean;
} }
async function run(options: RunOptions = {}) { async function run(options: RunOptions = {}) {
@@ -50,6 +49,19 @@ async function run(options: RunOptions = {}) {
// Save the PID of the background process // Save the PID of the background process
savePid(process.pid); savePid(process.pid);
// Handle SIGINT (Ctrl+C) to clean up PID file
process.on('SIGINT', () => {
console.log("Received SIGINT, cleaning up...");
cleanupPidFile();
process.exit(0);
});
// Handle SIGTERM to clean up PID file
process.on('SIGTERM', () => {
cleanupPidFile();
process.exit(0);
});
// Use port from environment variable if set (for background process) // Use port from environment variable if set (for background process)
const servicePort = process.env.SERVICE_PORT const servicePort = process.env.SERVICE_PORT
? parseInt(process.env.SERVICE_PORT) ? parseInt(process.env.SERVICE_PORT)

View File

@@ -1,21 +1,25 @@
import { isServiceRunning, cleanupPidFile } from './processCheck'; import { isServiceRunning, cleanupPidFile, getReferenceCount } from './processCheck';
import { existsSync, readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { homedir } from 'os'; import { HOME_DIR } from '../constants';
import { join } from 'path'; import { join } from 'path';
export async function closeService() { export async function closeService() {
const PID_FILE = join(homedir(), '.claude-code-router.pid'); const PID_FILE = join(HOME_DIR, '.claude-code-router.pid');
if (!isServiceRunning()) { if (!isServiceRunning()) {
console.log("No service is currently running."); console.log("No service is currently running.");
return; return;
} }
if (getReferenceCount() > 0) {
return;
}
try { try {
const pid = parseInt(readFileSync(PID_FILE, 'utf-8')); const pid = parseInt(readFileSync(PID_FILE, 'utf-8'));
process.kill(pid); process.kill(pid);
cleanupPidFile(); cleanupPidFile();
console.log("Service has been successfully stopped."); console.log("claude code router service has been successfully stopped.");
} catch (e) { } catch (e) {
console.log("Failed to stop the service. It may have already been stopped."); console.log("Failed to stop the service. It may have already been stopped.");
cleanupPidFile(); cleanupPidFile();

View File

@@ -1,5 +1,6 @@
import { spawn } from 'child_process'; import { spawn } from 'child_process';
import { isServiceRunning } from './processCheck'; import { isServiceRunning, incrementReferenceCount, decrementReferenceCount } from './processCheck';
import { closeService } from './close';
export async function executeCodeCommand(args: string[] = []) { export async function executeCodeCommand(args: string[] = []) {
// Service check is now handled in cli.ts // Service check is now handled in cli.ts
@@ -13,6 +14,9 @@ export async function executeCodeCommand(args: string[] = []) {
API_TIMEOUT_MS: '600000' API_TIMEOUT_MS: '600000'
}; };
// Increment reference count when command starts
incrementReferenceCount();
// Execute claude command // Execute claude command
const claudeProcess = spawn('claude', args, { const claudeProcess = spawn('claude', args, {
env, env,
@@ -23,10 +27,13 @@ export async function executeCodeCommand(args: string[] = []) {
claudeProcess.on('error', (error) => { claudeProcess.on('error', (error) => {
console.error('Failed to start claude command:', error.message); console.error('Failed to start claude command:', error.message);
console.log('Make sure Claude Code is installed: npm install -g @anthropic-ai/claude-code'); console.log('Make sure Claude Code is installed: npm install -g @anthropic-ai/claude-code');
decrementReferenceCount();
process.exit(1); process.exit(1);
}); });
claudeProcess.on('close', (code) => { claudeProcess.on('close', (code) => {
decrementReferenceCount();
closeService()
process.exit(code || 0); process.exit(code || 0);
}); });
} }

View File

@@ -1,6 +1,32 @@
import { existsSync, readFileSync, writeFileSync } from 'fs'; import { existsSync, readFileSync, writeFileSync } from 'fs';
import { PID_FILE } from '../constants'; import { PID_FILE } from '../constants';
const REFERENCE_COUNT_FILE = '/tmp/claude-code-reference-count.txt';
export function incrementReferenceCount() {
let count = 0;
if (existsSync(REFERENCE_COUNT_FILE)) {
count = parseInt(readFileSync(REFERENCE_COUNT_FILE, 'utf-8')) || 0;
}
count++;
writeFileSync(REFERENCE_COUNT_FILE, count.toString());
}
export function decrementReferenceCount() {
let count = 0;
if (existsSync(REFERENCE_COUNT_FILE)) {
count = parseInt(readFileSync(REFERENCE_COUNT_FILE, 'utf-8')) || 0;
}
count = Math.max(0, count - 1);
writeFileSync(REFERENCE_COUNT_FILE, count.toString());
}
export function getReferenceCount(): number {
if (!existsSync(REFERENCE_COUNT_FILE)) {
return 0;
}
return parseInt(readFileSync(REFERENCE_COUNT_FILE, 'utf-8')) || 0;
}
export function isServiceRunning(): boolean { export function isServiceRunning(): boolean {
if (!existsSync(PID_FILE)) { if (!existsSync(PID_FILE)) {
@@ -55,6 +81,7 @@ export function getServiceInfo() {
pid, pid,
port: 3456, port: 3456,
endpoint: 'http://127.0.0.1:3456', endpoint: 'http://127.0.0.1:3456',
pidFile: PID_FILE pidFile: PID_FILE,
referenceCount: getReferenceCount()
}; };
} }