@@ -40,5 +40,9 @@ MAX_QUBITS=32
|
||||
MAX_SHOTS=100000
|
||||
|
||||
# Python Bridge Configuration
|
||||
PYTHON_TIMEOUT=60000
|
||||
PYTHON_MEMORY_LIMIT=2048
|
||||
# Timeout for Python commands in milliseconds
|
||||
# Default: 300000 (5 minutes)
|
||||
# Increase for complex quantum operations or slower hardware
|
||||
PYTHON_TIMEOUT=300000
|
||||
PYTHON_MEMORY_LIMIT=2048
|
||||
```
|
||||
@@ -20,6 +20,7 @@ MCP_SERVER_VERSION=1.0.0
|
||||
CUDAQ_PYTHON_PATH=/usr/local/bin/python3
|
||||
CUDAQ_DEFAULT_TARGET=qpp-cpu
|
||||
CUDAQ_LOG_LEVEL=info
|
||||
PYTHON_TIMEOUT=300000
|
||||
|
||||
# GPU Configuration
|
||||
CUDA_VISIBLE_DEVICES=0
|
||||
@@ -36,6 +37,11 @@ MAX_CONCURRENT_JOBS=10
|
||||
QUANTUM_CIRCUIT_TIMEOUT=30000
|
||||
MAX_QUBITS=32
|
||||
MAX_SHOTS=100000
|
||||
|
||||
# Python Bridge Timeout (in milliseconds)
|
||||
# Default: 300000 (5 minutes)
|
||||
# Increase for complex quantum operations or slower hardware
|
||||
PYTHON_TIMEOUT=300000
|
||||
```
|
||||
|
||||
### Claude Desktop Integration
|
||||
|
||||
19
README.md
19
README.md
@@ -89,6 +89,11 @@ CUDAQ_PYTHON_PATH=/usr/local/bin/python3
|
||||
CUDAQ_DEFAULT_TARGET=qpp-cpu
|
||||
CUDAQ_LOG_LEVEL=info
|
||||
|
||||
# Python Bridge Timeout (milliseconds)
|
||||
# Default: 300000 (5 minutes)
|
||||
# Increase for complex operations or slower hardware
|
||||
PYTHON_TIMEOUT=300000
|
||||
|
||||
# GPU Configuration
|
||||
CUDA_VISIBLE_DEVICES=0
|
||||
CUDAQ_ENABLE_GPU=true
|
||||
@@ -487,13 +492,19 @@ Solution:
|
||||
|
||||
#### Python Bridge Timeout
|
||||
```bash
|
||||
Error: Python command timeout
|
||||
Error: Python command timeout after Xms
|
||||
Solution:
|
||||
1. Increase timeout in config
|
||||
2. Check Python path in .env
|
||||
3. Ensure CUDA Quantum installation
|
||||
1. Increase timeout with environment variable:
|
||||
export PYTHON_TIMEOUT=600000 # 10 minutes in milliseconds
|
||||
2. Check Python path in .env:
|
||||
CUDAQ_PYTHON_PATH=/usr/local/bin/python3
|
||||
3. Ensure CUDA Quantum is properly installed:
|
||||
python3 -c "import cudaq; print(cudaq.__version__)"
|
||||
4. Check for Python process errors in logs
|
||||
```
|
||||
|
||||
**Note**: The default timeout is 300,000ms (5 minutes). Complex quantum operations or slower hardware may require increasing this value via the `PYTHON_TIMEOUT` environment variable.
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug logging:
|
||||
|
||||
@@ -539,11 +539,18 @@ def main():
|
||||
|
||||
if command:
|
||||
result = dispatch_command(command, **data)
|
||||
response = {
|
||||
"success": True,
|
||||
"data": result,
|
||||
"requestId": request_id
|
||||
}
|
||||
|
||||
# Check if the result already has success/error structure
|
||||
if isinstance(result, dict) and ("success" in result or "error" in result):
|
||||
# Result already has proper structure, just add request ID
|
||||
response = {**result, "requestId": request_id}
|
||||
else:
|
||||
# Wrap result in standard response structure
|
||||
response = {
|
||||
"success": True,
|
||||
"data": result,
|
||||
"requestId": request_id
|
||||
}
|
||||
print(f"DEBUG - Command {command} completed successfully", file=sys.stderr, flush=True)
|
||||
else:
|
||||
response = {
|
||||
@@ -552,7 +559,10 @@ def main():
|
||||
"requestId": request_id
|
||||
}
|
||||
|
||||
print(json.dumps(response), flush=True)
|
||||
# Ensure response is sent on a single line with explicit flush
|
||||
output = json.dumps(response)
|
||||
print(output, flush=True)
|
||||
sys.stdout.flush() # Extra flush to ensure it's sent
|
||||
|
||||
except Exception as e:
|
||||
print(f"ERROR - Exception in main loop: {str(e)}", file=sys.stderr, flush=True)
|
||||
@@ -563,7 +573,9 @@ def main():
|
||||
"traceback": traceback.format_exc(),
|
||||
"requestId": request.get("requestId", "") if 'request' in locals() else ""
|
||||
}
|
||||
print(json.dumps(error_response), flush=True)
|
||||
output = json.dumps(error_response)
|
||||
print(output, flush=True)
|
||||
sys.stdout.flush() # Extra flush to ensure it's sent
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -38,10 +38,15 @@ export class PythonBridge extends EventEmitter {
|
||||
constructor(config: PythonBridgeConfig = {}) {
|
||||
super();
|
||||
|
||||
// Get timeout from environment variable or use default
|
||||
const defaultTimeout = process.env.PYTHON_TIMEOUT
|
||||
? parseInt(process.env.PYTHON_TIMEOUT, 10)
|
||||
: 300000; // Default 5 minutes
|
||||
|
||||
this.config = {
|
||||
pythonPath: config.pythonPath || process.env.CUDAQ_PYTHON_PATH || 'python3',
|
||||
scriptPath: config.scriptPath || path.join(process.cwd(), 'python/cudaq_bridge.py'),
|
||||
timeout: config.timeout || 60000,
|
||||
timeout: config.timeout || defaultTimeout,
|
||||
maxMemory: config.maxMemory || 2048
|
||||
};
|
||||
|
||||
@@ -102,14 +107,21 @@ export class PythonBridge extends EventEmitter {
|
||||
|
||||
// Log stderr messages but don't treat them as fatal errors during initialization
|
||||
// Most Python logging goes to stderr even for non-errors
|
||||
if (error.includes('WARNING') || error.includes('INFO') || error.includes('DEBUG')) {
|
||||
this.logger.debug('Python log message:', error);
|
||||
} else if (error.trim()) {
|
||||
this.logger.error('Python stderr:', error);
|
||||
// Only reject during initialization if it's a real error (not a log message)
|
||||
if (!initialized && !error.includes('INFO') && !error.includes('WARNING') && !error.includes('DEBUG')) {
|
||||
if (error.includes('DEBUG')) {
|
||||
this.logger.debug('Python debug:', error.trim());
|
||||
} else if (error.includes('WARNING')) {
|
||||
this.logger.warn('Python warning:', error.trim());
|
||||
} else if (error.includes('INFO')) {
|
||||
this.logger.info('Python info:', error.trim());
|
||||
} else if (error.includes('ERROR')) {
|
||||
this.logger.error('Python error:', error.trim());
|
||||
// Only reject during initialization if it's a real error
|
||||
if (!initialized) {
|
||||
reject(new Error(`Python process error: ${error}`));
|
||||
}
|
||||
} else if (error.trim()) {
|
||||
// Unknown stderr output - log as debug
|
||||
this.logger.debug('Python stderr:', error.trim());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -147,16 +159,25 @@ export class PythonBridge extends EventEmitter {
|
||||
try {
|
||||
const response = JSON.parse(line);
|
||||
|
||||
if (response.request_id) {
|
||||
const pending = this.requestQueue.get(response.request_id);
|
||||
// Handle both requestId and request_id for compatibility
|
||||
const reqId = response.requestId || response.request_id;
|
||||
|
||||
if (reqId) {
|
||||
const pending = this.requestQueue.get(reqId);
|
||||
if (pending) {
|
||||
this.logger.debug(`Received response for request ${reqId}`);
|
||||
clearTimeout(pending.timeout);
|
||||
this.requestQueue.delete(response.request_id);
|
||||
this.requestQueue.delete(reqId);
|
||||
pending.resolve(response);
|
||||
} else {
|
||||
this.logger.warn(`Received response for unknown request ${reqId}`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore non-JSON lines
|
||||
// Ignore non-JSON lines (debug logs, etc.)
|
||||
if (!line.includes('DEBUG') && !line.includes('INFO') && !line.includes('WARNING')) {
|
||||
this.logger.debug('Non-JSON output from Python:', line);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -172,30 +193,37 @@ export class PythonBridge extends EventEmitter {
|
||||
const requestId = Math.random().toString(36).substring(2, 15);
|
||||
const request = { command, data, requestId };
|
||||
|
||||
// Set timeout based on command complexity
|
||||
let timeoutDuration = 5000; // Default 5s
|
||||
// Use environment variable timeout for all commands
|
||||
// This allows users to adjust based on hardware capabilities
|
||||
const timeoutDuration = this.config.timeout;
|
||||
|
||||
this.logger.debug(`Sending command '${command}' with request ID ${requestId} (timeout: ${timeoutDuration}ms)`);
|
||||
|
||||
if (command === 'set_target') {
|
||||
timeoutDuration = 100000; // 100s for target operations
|
||||
} else if (['sample', 'observe', 'get_state'].includes(command)) {
|
||||
timeoutDuration = 150000; // 150s for quantum operations
|
||||
} else if (['get_platform_info', 'get_available_targets', 'list_kernels'].includes(command)) {
|
||||
timeoutDuration = 30000; // 30s for simple info operations
|
||||
}
|
||||
const timeout = setTimeout(() => {
|
||||
this.requestQueue.delete(requestId);
|
||||
reject(new Error(`Python command timeout: ${command}`));
|
||||
this.logger.error(`Command '${command}' timed out after ${timeoutDuration}ms (request ID: ${requestId})`);
|
||||
reject(new Error(`Python command timeout after ${timeoutDuration}ms: ${command}`));
|
||||
}, timeoutDuration);
|
||||
|
||||
// Store request with timeout for cleanup
|
||||
this.requestQueue.set(requestId, { resolve, reject, timeout });
|
||||
|
||||
if (!this.pythonProcess) {
|
||||
clearTimeout(timeout);
|
||||
this.requestQueue.delete(requestId);
|
||||
reject(new Error('Python process not initialized'));
|
||||
return;
|
||||
}
|
||||
|
||||
this.pythonProcess.stdin?.write(JSON.stringify(request) + '\n');
|
||||
try {
|
||||
this.pythonProcess.stdin?.write(JSON.stringify(request) + '\n');
|
||||
this.logger.debug(`Command '${command}' sent successfully`);
|
||||
} catch (error) {
|
||||
clearTimeout(timeout);
|
||||
this.requestQueue.delete(requestId);
|
||||
this.logger.error(`Failed to send command '${command}':`, error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Referencia en una nueva incidencia
Block a user