From 84e76f24b04384b98b3a544f6d44ce0d8a02bd6b Mon Sep 17 00:00:00 2001 From: "jinhui.li" Date: Thu, 12 Jun 2025 09:58:05 +0800 Subject: [PATCH] fix the issue of multiple calude using one server by claude code --- src/cli.ts | 10 +++++++--- src/index.ts | 18 +++++++++++++++--- src/utils/close.ts | 14 +++++++++----- src/utils/codeCommand.ts | 9 ++++++++- src/utils/processCheck.ts | 29 ++++++++++++++++++++++++++++- 5 files changed, 67 insertions(+), 13 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index bd47cc5..2a575cd 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -43,10 +43,12 @@ async function waitForService( return false; } +import { spawn } from "child_process"; + async function main() { switch (command) { case "start": - await run({ daemon: true }); + run(); break; case "stop": await closeService(); @@ -57,8 +59,10 @@ async function main() { case "code": if (!isServiceRunning()) { console.log("Service not running, starting service..."); - await run({ daemon: true }); - // Wait for service to start, exit with error if timeout + spawn("ccr", ["start"], { + detached: true, + stdio: "ignore", + }).unref(); if (await waitForService()) { executeCodeCommand(process.argv.slice(3)); } else { diff --git a/src/index.ts b/src/index.ts index 498d0b8..6134dc0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,8 +6,8 @@ import { formatRequest } from "./middlewares/formatRequest"; import { rewriteBody } from "./middlewares/rewriteBody"; import OpenAI from "openai"; import { streamOpenAIResponse } from "./utils/stream"; -import { isServiceRunning, savePid } from "./utils/processCheck"; -import { fork } from "child_process"; +import { cleanupPidFile, isServiceRunning, savePid } from "./utils/processCheck"; + async function initializeClaudeConfig() { const homeDir = process.env.HOME; @@ -31,7 +31,6 @@ async function initializeClaudeConfig() { interface RunOptions { port?: number; - daemon?: boolean; } async function run(options: RunOptions = {}) { @@ -50,6 +49,19 @@ async function run(options: RunOptions = {}) { // Save the PID of the background process 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) const servicePort = process.env.SERVICE_PORT ? parseInt(process.env.SERVICE_PORT) diff --git a/src/utils/close.ts b/src/utils/close.ts index b0368da..6c1f973 100644 --- a/src/utils/close.ts +++ b/src/utils/close.ts @@ -1,21 +1,25 @@ -import { isServiceRunning, cleanupPidFile } from './processCheck'; -import { existsSync, readFileSync } from 'fs'; -import { homedir } from 'os'; +import { isServiceRunning, cleanupPidFile, getReferenceCount } from './processCheck'; +import { readFileSync } from 'fs'; +import { HOME_DIR } from '../constants'; import { join } from 'path'; 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()) { console.log("No service is currently running."); return; } + if (getReferenceCount() > 0) { + return; + } + try { const pid = parseInt(readFileSync(PID_FILE, 'utf-8')); process.kill(pid); cleanupPidFile(); - console.log("Service has been successfully stopped."); + console.log("claude code router service has been successfully stopped."); } catch (e) { console.log("Failed to stop the service. It may have already been stopped."); cleanupPidFile(); diff --git a/src/utils/codeCommand.ts b/src/utils/codeCommand.ts index 61e840b..b333d9c 100644 --- a/src/utils/codeCommand.ts +++ b/src/utils/codeCommand.ts @@ -1,5 +1,6 @@ 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[] = []) { // Service check is now handled in cli.ts @@ -13,6 +14,9 @@ export async function executeCodeCommand(args: string[] = []) { API_TIMEOUT_MS: '600000' }; + // Increment reference count when command starts + incrementReferenceCount(); + // Execute claude command const claudeProcess = spawn('claude', args, { env, @@ -23,10 +27,13 @@ export async function executeCodeCommand(args: string[] = []) { claudeProcess.on('error', (error) => { console.error('Failed to start claude command:', error.message); console.log('Make sure Claude Code is installed: npm install -g @anthropic-ai/claude-code'); + decrementReferenceCount(); process.exit(1); }); claudeProcess.on('close', (code) => { + decrementReferenceCount(); + closeService() process.exit(code || 0); }); } diff --git a/src/utils/processCheck.ts b/src/utils/processCheck.ts index 152acf1..f4a4394 100644 --- a/src/utils/processCheck.ts +++ b/src/utils/processCheck.ts @@ -1,6 +1,32 @@ import { existsSync, readFileSync, writeFileSync } from 'fs'; 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 { if (!existsSync(PID_FILE)) { @@ -55,6 +81,7 @@ export function getServiceInfo() { pid, port: 3456, endpoint: 'http://127.0.0.1:3456', - pidFile: PID_FILE + pidFile: PID_FILE, + referenceCount: getReferenceCount() }; }