Heroku中Express路由执行Python脚本时出现H12请求超时错误求助
Hey Winston, let's break down why you're hitting that H12 timeout error on Heroku and fix it step by step.
What's Causing the H12 Timeout?
First, let's unpack the key issues in your code and setup:
- Broken parameter passing: When you pass
dataIntdirectly tospawn('python', ["./predict.py", dataInt]), Node.js treats every element in the array as a separate command-line argument. Your Python script is almost certainly not expecting this, so it's probably getting stuck trying to parse invalid input instead of returning a result. - Incomplete process handling: You're only listening to the
stdoutstream, but you're not handling errors, script crashes, or the process finishing. If the Python script hangs or fails silently, your Express route will never send a response, leading to the 30-second timeout Heroku enforces. - Potential performance bottlenecks: If
predict.pyruns a machine learning model, Heroku's free/basic dynos have limited CPU/memory. If the script takes longer than 30 seconds to run, you'll hit the timeout every time.
Fixes to Implement
1. Fix How You Pass Data to Python
Instead of passing an array as multiple arguments, serialize your data into a single JSON string. This makes it easy for Python to parse correctly:
// In your Express route function sendPrediction(dataInf) { // Convert the integer array to a single JSON string parameter const dataParam = JSON.stringify(dataInt); const process = spawn('python', ["./predict.py", dataParam]); // Rest of your process handling goes here... }
Then update predict.py to parse this JSON parameter:
import sys import json if __name__ == "__main__": # Read the JSON string from command line args input_data = json.loads(sys.argv[1]) # Run your prediction logic with input_data... # Print your result as JSON (so Node can parse it easily) print(json.dumps(your_prediction_result))
2. Complete Process Event Handling
You need to listen to all critical events from the Python process to ensure you always send a response to the client:
function sendPrediction(dataInf) { const dataParam = JSON.stringify(dataInt); const process = spawn('python', ["./predict.py", dataParam]); let stdoutOutput = ''; let stderrOutput = ''; // Capture standard output process.stdout.on('data', (data) => { stdoutOutput += data.toString('utf-8'); }); // Capture error output (critical for debugging) process.stderr.on('data', (data) => { stderrOutput += data.toString('utf-8'); }); // Handle process completion process.on('close', (exitCode) => { if (exitCode !== 0) { return res.status(500).json({ error: 'Python script failed', details: stderrOutput.trim() }); } try { // Parse Python's JSON output and send it back const predictionResult = JSON.parse(stdoutOutput.trim()); res.json(predictionResult); } catch (parseErr) { // If parsing fails, send the raw output (for debugging) res.send(stdoutOutput.trim()); } }); // Handle cases where the process can't start at all process.on('error', (err) => { res.status(500).json({ error: 'Failed to launch Python process', details: err.message }); }); }
3. Optimize for Heroku's Limits
If your Python script is slow (e.g., large ML model):
- Optimize the model: Use model quantization, smaller architectures, or precompute where possible to cut down runtime.
- Use background processing: Move the prediction task to a Heroku Worker dyno. Use a queue (like Redis + BullMQ) to send jobs from your Web dyno, then let the Worker handle the slow task. The Web dyno can return a "processing" status immediately, and the client can poll for results later.
4. Verify Heroku Environment Setup
Make sure Heroku can run your Python script:
- Add a
runtime.txtfile to specify your Python version (e.g.,python-3.10.12). - Add a
requirements.txtfile listing all Python dependencies (e.g.,scikit-learn==1.2.2). - Check your Heroku logs with
heroku logs --tailto see if the Python script is throwing errors you can't see locally.
内容的提问来源于stack exchange,提问作者Winston Chan
相关产品推荐
相关产品推荐

