英文:
NodeJS Lambda Return result from inside a promise
问题
我有一个使用mysql库来选择数据并将其作为结果检索的NodeJS Lambda函数。它通过API Gateway的HTTP调用触发。
但我似乎找不到一种将查询结果作为调用的响应返回的方法。
这是示例代码:
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const mysql = require('mysql');
const con = mysql.createConnection({
host: process.env.RDS_HOSTNAME,
user: process.env.RDS_USERNAME,
password: process.env.RDS_PASSWORD,
port: process.env.RDS_PORT,
database: process.env.RDS_DATABASE,
});
const tableName = 'fit_guide';
export const handler = async (event, context, callback) => {
let response = {};
const routeKey = event.routeKey;
let sql = `SELECT * FROM ${tableName}`;
con.query(sql, function (error, results, fields) {
if (error) throw error;
// 这里会打印数据库表的结果
console.log('******** ', results);
// 但这里不会返回结果
response = {
statusCode: 200,
success: true,
results,
};
callback(null, JSON.stringify(response));
return response;
});
con.end();
// 这里会返回一个空对象 {}(初始值)
callback(null, JSON.stringify(response));
return response;
};
如何在查询执行中返回响应,而不是对象的初始值?
英文:
I have a NodeJS lambda function that uses the mysql library for selecting data and retrieve it as a result. It gets triggered via an API Gateway http call.
But I can't seem to find a way to return the result of the query as the response of the call.
This is the sample code:
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const mysql = require('mysql');
const con = mysql.createConnection({
host: process.env.RDS_HOSTNAME,
user: process.env.RDS_USERNAME,
password: process.env.RDS_PASSWORD,
port: process.env.RDS_PORT,
database: process.env.RDS_DATABASE,
});
const tableName = 'fit_guide';
export const handler = async (event, context, callback) => {
let response = {};
const routeKey = event.routeKey;
let sql = `SELECT * FROM ${tableName}`;
con.query(sql, function (error, results, fields) {
if (error) throw error;
// THIS DOES PRINT THE RESULTS FROM THE DATABASE TABLE
console.log('******** ', results);
// THIS DOESN'T RETURN
response = {
statusCode: 200,
success: true,
results,
};
callback(null, JSON.stringify(response));
return response;
});
con.end();
// THIS RETURNS AN EMPTY OBJECT {} (initial value)
callback(null, JSON.stringify(response));
return response;
};
How can I return the response inside the query execution rather than the initial value of the object?
答案1
得分: 1
您的处理程序存在竞态条件。return response;
行在查询和 Lambda callback
有机会执行之前返回了{}
。最简单的修复方法是移除 return response;
。
这个竞态条件存在是因为您的代码混合了 Lambda 非异步(回调,没有返回值)和异步(没有回调,返回Promise<Something>
)处理程序模式。如当前编写的,返回值在竞争中胜出了回调。您应该只使用一种模式,而不是同时使用两种。
以下是一个类似于您的竞态条件的演示(不要在家里尝试这样做!)。如当前编写的,消息将是 Callback wins!
,因为回调会在短时间延迟后触发,而 Promise 只在1秒后解析。添加2秒的回调延迟将得到 Promise return wins!
。当然,修复方法是移除其中一个,除非您真的喜欢竞赛。
export const raceHandler = async (
context: Context,
event: APIGatewayProxyEventV2,
callback: APIGatewayProxyCallbackV2
): Promise<APIGatewayProxyResultV2> => {
// Race contestant 1: callback with delay - simulates your MySQL query
setTimeout(() => {
callback(null, {
statusCode: 200,
body: JSON.stringify({ message: "Callback wins!" }),
});
}, 10);
// Race contestant 2: Promise return resolution with delay
return new Promise((resolve) => {
setTimeout(() => {
resolve({
statusCode: 200,
body: JSON.stringify({ message: "Promise return wins!" }),
});
}, 1000);
});
};
英文:
TL; DR Your handler has a race condition. The return response;
line returns {}
before your query and the Lambda callback
have a chance to execute. The easist fix is to remove return response;
.
The race condition exists because your code mixes the Lambda Non-Async (callback, no return value) and Async (no callback, return Promise<Something>
) handler patterns. As currently written, the return value is winning the race against the callback. You should use one pattern or the other, not both.
Here is a demo with a race condition like yours (Don't try this at home, kids!). As written, the message will be Callback wins!
because the callback fires with a short delay, while the Promise resolves only after 1 second. Add a 2 second callback delay to get Promise return wins!
. Of course, the fix is to remove one or the other, unless you really enjoy a race.
export const raceHandler = async (
context: Context,
event: APIGatewayProxyEventV2,
callback: APIGatewayProxyCallbackV2
): Promise<APIGatewayProxyResultV2> => {
// Race contestant 1: callback with delay - simulates your MySQL query
setTimeout(() => {
callback(null, {
statusCode: 200,
body: JSON.stringify({ message: "Callback wins!" }),
});
}, 10);
// Race contestant 2: Promise return resolution with delay
return new Promise((resolve) => {
setTimeout(() => {
resolve({
statusCode: 200,
body: JSON.stringify({ message: "Promise return wins!" }),
});
}, 1000);
});
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论