@@ -40,5 +40,9 @@ MAX_QUBITS=32
|
|||||||
MAX_SHOTS=100000
|
MAX_SHOTS=100000
|
||||||
|
|
||||||
# Python Bridge Configuration
|
# Python Bridge Configuration
|
||||||
PYTHON_TIMEOUT=60000
|
# 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
|
PYTHON_MEMORY_LIMIT=2048
|
||||||
|
```
|
||||||
@@ -20,6 +20,7 @@ MCP_SERVER_VERSION=1.0.0
|
|||||||
CUDAQ_PYTHON_PATH=/usr/local/bin/python3
|
CUDAQ_PYTHON_PATH=/usr/local/bin/python3
|
||||||
CUDAQ_DEFAULT_TARGET=qpp-cpu
|
CUDAQ_DEFAULT_TARGET=qpp-cpu
|
||||||
CUDAQ_LOG_LEVEL=info
|
CUDAQ_LOG_LEVEL=info
|
||||||
|
PYTHON_TIMEOUT=300000
|
||||||
|
|
||||||
# GPU Configuration
|
# GPU Configuration
|
||||||
CUDA_VISIBLE_DEVICES=0
|
CUDA_VISIBLE_DEVICES=0
|
||||||
@@ -36,6 +37,11 @@ MAX_CONCURRENT_JOBS=10
|
|||||||
QUANTUM_CIRCUIT_TIMEOUT=30000
|
QUANTUM_CIRCUIT_TIMEOUT=30000
|
||||||
MAX_QUBITS=32
|
MAX_QUBITS=32
|
||||||
MAX_SHOTS=100000
|
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
|
### 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_DEFAULT_TARGET=qpp-cpu
|
||||||
CUDAQ_LOG_LEVEL=info
|
CUDAQ_LOG_LEVEL=info
|
||||||
|
|
||||||
|
# Python Bridge Timeout (milliseconds)
|
||||||
|
# Default: 300000 (5 minutes)
|
||||||
|
# Increase for complex operations or slower hardware
|
||||||
|
PYTHON_TIMEOUT=300000
|
||||||
|
|
||||||
# GPU Configuration
|
# GPU Configuration
|
||||||
CUDA_VISIBLE_DEVICES=0
|
CUDA_VISIBLE_DEVICES=0
|
||||||
CUDAQ_ENABLE_GPU=true
|
CUDAQ_ENABLE_GPU=true
|
||||||
@@ -487,13 +492,19 @@ Solution:
|
|||||||
|
|
||||||
#### Python Bridge Timeout
|
#### Python Bridge Timeout
|
||||||
```bash
|
```bash
|
||||||
Error: Python command timeout
|
Error: Python command timeout after Xms
|
||||||
Solution:
|
Solution:
|
||||||
1. Increase timeout in config
|
1. Increase timeout with environment variable:
|
||||||
2. Check Python path in .env
|
export PYTHON_TIMEOUT=600000 # 10 minutes in milliseconds
|
||||||
3. Ensure CUDA Quantum installation
|
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
|
### Debug Mode
|
||||||
|
|
||||||
Enable debug logging:
|
Enable debug logging:
|
||||||
|
|||||||
@@ -539,11 +539,18 @@ def main():
|
|||||||
|
|
||||||
if command:
|
if command:
|
||||||
result = dispatch_command(command, **data)
|
result = dispatch_command(command, **data)
|
||||||
response = {
|
|
||||||
"success": True,
|
# Check if the result already has success/error structure
|
||||||
"data": result,
|
if isinstance(result, dict) and ("success" in result or "error" in result):
|
||||||
"requestId": request_id
|
# 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)
|
print(f"DEBUG - Command {command} completed successfully", file=sys.stderr, flush=True)
|
||||||
else:
|
else:
|
||||||
response = {
|
response = {
|
||||||
@@ -552,7 +559,10 @@ def main():
|
|||||||
"requestId": request_id
|
"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:
|
except Exception as e:
|
||||||
print(f"ERROR - Exception in main loop: {str(e)}", file=sys.stderr, flush=True)
|
print(f"ERROR - Exception in main loop: {str(e)}", file=sys.stderr, flush=True)
|
||||||
@@ -563,7 +573,9 @@ def main():
|
|||||||
"traceback": traceback.format_exc(),
|
"traceback": traceback.format_exc(),
|
||||||
"requestId": request.get("requestId", "") if 'request' in locals() else ""
|
"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__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -38,10 +38,15 @@ export class PythonBridge extends EventEmitter {
|
|||||||
constructor(config: PythonBridgeConfig = {}) {
|
constructor(config: PythonBridgeConfig = {}) {
|
||||||
super();
|
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 = {
|
this.config = {
|
||||||
pythonPath: config.pythonPath || process.env.CUDAQ_PYTHON_PATH || 'python3',
|
pythonPath: config.pythonPath || process.env.CUDAQ_PYTHON_PATH || 'python3',
|
||||||
scriptPath: config.scriptPath || path.join(process.cwd(), 'python/cudaq_bridge.py'),
|
scriptPath: config.scriptPath || path.join(process.cwd(), 'python/cudaq_bridge.py'),
|
||||||
timeout: config.timeout || 60000,
|
timeout: config.timeout || defaultTimeout,
|
||||||
maxMemory: config.maxMemory || 2048
|
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
|
// Log stderr messages but don't treat them as fatal errors during initialization
|
||||||
// Most Python logging goes to stderr even for non-errors
|
// Most Python logging goes to stderr even for non-errors
|
||||||
if (error.includes('WARNING') || error.includes('INFO') || error.includes('DEBUG')) {
|
if (error.includes('DEBUG')) {
|
||||||
this.logger.debug('Python log message:', error);
|
this.logger.debug('Python debug:', error.trim());
|
||||||
} else if (error.trim()) {
|
} else if (error.includes('WARNING')) {
|
||||||
this.logger.error('Python stderr:', error);
|
this.logger.warn('Python warning:', error.trim());
|
||||||
// Only reject during initialization if it's a real error (not a log message)
|
} else if (error.includes('INFO')) {
|
||||||
if (!initialized && !error.includes('INFO') && !error.includes('WARNING') && !error.includes('DEBUG')) {
|
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}`));
|
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 {
|
try {
|
||||||
const response = JSON.parse(line);
|
const response = JSON.parse(line);
|
||||||
|
|
||||||
if (response.request_id) {
|
// Handle both requestId and request_id for compatibility
|
||||||
const pending = this.requestQueue.get(response.request_id);
|
const reqId = response.requestId || response.request_id;
|
||||||
|
|
||||||
|
if (reqId) {
|
||||||
|
const pending = this.requestQueue.get(reqId);
|
||||||
if (pending) {
|
if (pending) {
|
||||||
|
this.logger.debug(`Received response for request ${reqId}`);
|
||||||
clearTimeout(pending.timeout);
|
clearTimeout(pending.timeout);
|
||||||
this.requestQueue.delete(response.request_id);
|
this.requestQueue.delete(reqId);
|
||||||
pending.resolve(response);
|
pending.resolve(response);
|
||||||
|
} else {
|
||||||
|
this.logger.warn(`Received response for unknown request ${reqId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} 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) {
|
} catch (error) {
|
||||||
@@ -172,30 +193,37 @@ export class PythonBridge extends EventEmitter {
|
|||||||
const requestId = Math.random().toString(36).substring(2, 15);
|
const requestId = Math.random().toString(36).substring(2, 15);
|
||||||
const request = { command, data, requestId };
|
const request = { command, data, requestId };
|
||||||
|
|
||||||
// Set timeout based on command complexity
|
// Use environment variable timeout for all commands
|
||||||
let timeoutDuration = 5000; // Default 5s
|
// 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(() => {
|
const timeout = setTimeout(() => {
|
||||||
this.requestQueue.delete(requestId);
|
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);
|
}, timeoutDuration);
|
||||||
|
|
||||||
// Store request with timeout for cleanup
|
// Store request with timeout for cleanup
|
||||||
this.requestQueue.set(requestId, { resolve, reject, timeout });
|
this.requestQueue.set(requestId, { resolve, reject, timeout });
|
||||||
|
|
||||||
if (!this.pythonProcess) {
|
if (!this.pythonProcess) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
this.requestQueue.delete(requestId);
|
||||||
reject(new Error('Python process not initialized'));
|
reject(new Error('Python process not initialized'));
|
||||||
return;
|
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