如何在Lambda函数中实现NodeJS 12调用Python 3.7及自定义运行时?
Great question! Let's break down how to make Node.js 12 Lambda functions call Python 3.7 code efficiently—perfect for those long-running API calls where Node.js's promise-based async model can shine. The simplest approach doesn't require building a full custom runtime; instead, we'll use a Lambda Layer to package the Python 3.7 environment and dependencies, then call Python scripts directly from Node.js using child processes.
1. 准备Python 3.7环境与依赖的Lambda Layer
Lambda runs Node.js 12 on Amazon Linux 2, so we need to build our Python environment in a matching OS context to avoid compatibility issues. Here's how to do it with Docker (no need for a local Amazon Linux machine):
- Spin up an Amazon Linux 2 container:
docker run -it --rm amazonlinux:2 bash - Inside the container, install Python 3.7 and pip:
yum install -y python37 python37-pip - Create a directory structure for the Layer, then install your Python dependencies into it:
mkdir -p python/lib/python3.7/site-packages pip3.7 install requests [your-other-dependencies] -t python/lib/python3.7/site-packages - Package the directory into a zip file (this will be your Layer):
zip -r python37-layer.zip python/ - Exit the Docker container, then upload
python37-layer.zipas a new Lambda Layer in the AWS Console. When configuring the Layer, set the compatible runtime tonodejs12.x(even though it's a Python environment—Layers just provide files, not runtime enforcement).
2. 编写Node.js代码调用Python脚本
Now you can write your Node.js handler to spawn a Python process for the long-running API calls, wrapping it in a promise to leverage Node.js's async capabilities.
Example Python script (api_caller.py)
Place this in your Lambda function's code directory:
import requests import sys import json def fetch_data(): # Replace with your long-running API call logic response = requests.get("https://example.com/your-slow-api") return response.json() if __name__ == "__main__": try: result = fetch_data() print(json.dumps(result)) sys.exit(0) except Exception as e: print(json.dumps({"error": str(e)})) sys.exit(1)
Example Node.js handler
Use the child_process.spawn method to run the Python script, wrapped in a promise:
const { spawn } = require('child_process'); const path = require('path'); exports.handler = async (event) => { // Wrapper function to run Python script as a promise const runPython = () => { return new Promise((resolve, reject) => { // Path to Python 3.7 in the Layer (Lambda mounts Layers at /opt) const pythonPath = '/opt/python/bin/python3.7'; const scriptPath = path.join(__dirname, 'api_caller.py'); const process = spawn(pythonPath, [scriptPath]); let stdout = ''; let stderr = ''; process.stdout.on('data', (data) => stdout += data.toString()); process.stderr.on('data', (data) => stderr += data.toString()); process.on('close', (code) => { if (code === 0) { try { const result = JSON.parse(stdout); resolve(result); } catch (parseErr) { reject(new Error(`Failed to parse Python output: ${parseErr.message}`)); } } else { reject(new Error(`Python script failed (code ${code}): ${stderr}`)); } }); }); }; try { const apiResult = await runPython(); return { statusCode: 200, body: JSON.stringify({ success: true, data: apiResult }) }; } catch (err) { return { statusCode: 500, body: JSON.stringify({ success: false, error: err.message }) }; } };
3. 关于自定义运行时的说明
If you were considering a full custom runtime (instead of the Layer + child process approach), know that it's far more complex for this use case. Custom runtimes require a bootstrap script that handles Lambda's event loop, and you'd need to package both Node.js 12 and Python 3.7 into the runtime. This is overkill unless you need deep integration between the two languages—stick with the Layer approach for simplicity.
4. 官方与可用运行时列表
AWS Lambda's officially supported runtimes (as of 2024) include:
- Node.js: 14.x, 16.x, 18.x, 20.x (Note: Node.js 12 is end-of-life and no longer supported by AWS—you should upgrade to a newer version as soon as possible)
- Python: 3.8, 3.9, 3.10, 3.11
- Java: 8, 11, 17
- .NET: 6, 8
- Go: 1.x
- Ruby: 2.7, 3.2
- Custom Runtime: Allows you to bring any language/environment (but requires the bootstrap script)
Third-party community Layers for Node.js 12 + Python 3.7 are rare these days due to Node.js 12 being deprecated, so building your own Layer is the most reliable path.
内容的提问来源于stack exchange,提问作者Guillaume

