从 lambda 向 sns 主题发布消息
publish a message to a sns topic from lambda
我有一个 lambda 函数,它通过 AWS lambda 函数处理 POST 请求。它处理 post 请求的主体并进行查询并 return 做出响应。
我的 LAMBDA 函数
const { Pool, Client } = require("pg");
const userName = 'blah';
const hostEndPoint = 'blah';
const databaseType = 'blahblah';
const pwd = 'pass pass';
const portNumber = 5432;
var AWS = require('aws-sdk');
const pool = new Pool({
user: userName,
host: hostEndPoint,
database: databaseType,
password: pwd,
port: portNumber
});
exports.handler = async (event) => {
let body = JSON.parse(event.body);
let name = body.name;
let money = body.money;
let todayDate = new Date();
var status = 0;
let text = 'INSERT INTO employee(name, date, salary) VALUES(, , ) RETURNING *';
let values = [name, todayDate, money];
var message = '';
var status = 0;
try {
const res = await pool.query(text, values)
message += 'successful'
status = 200;
} catch (err) {
message += 'unsuccessful'
if (err.code === '23505') {
status = 406;
}
}
var params = {
Message: 'Hello From Lambda', /* required */
TopicArn: 'arn:aws:sns:us-east-1:blahblahblah'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({ apiVersion: '2010-03-31' }).publish(params).promise();
publishTextPromise.then(
function (data) {
console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
console.log("MessageID is " + data.MessageId);
}).catch(
function (err) {
console.error(err, err.stack);
});
const response = {
statusCode: status,
body: JSON.stringify(message),
headers: {
"Access-Control-Allow-Origtin": '*'
}
};
return response;
};
我的 Lambda 资源策略 看起来像这样
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "blah-blah-blah-blah",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:blah-blah-blah-blah-blah",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:execute-api:us-east-1:blahblahblahblha:blah/*/POST/"
}
}
}
]
}
我还创建了一个 SNS 主题。如果我的状态是 200,我想向 SNS 主题发布消息。所以在我 return 响应之前。我想做这样的事情。
if (status === 200){
pubish some message to my sns topic
}
我是 aws 的新手,希望获得有关如何发布消息的指导。我觉得我很亲近。我确实遇到过这个 topic 但它让我感到困惑,因为我正在 lambda 函数中编辑代码,所以为什么我需要要求 aws-sdk 而且他们也没有谈论更改权限。
尝试以下建议的答案后更新了代码
我假设你的架构看起来像这样:
API-Gateway 接受请求并调用您向我们展示的 lambda 函数。
该 Lambda 函数连接到数据库并插入一条记录。您现在希望此 Lambda 函数也发布到 SNS 主题。
为此,您需要做两件事:
- 授予 Lambda 函数对 SNS 主题的权限
- 编写代码向主题发布消息
步骤 1 应该放在第一位,为此您需要编辑您的函数正在使用的 IAM 角色。 IAM 角色指定允许此 lambda 函数调用哪些 AWS 服务。您向我们展示的 Lambda 资源策略授予 API 网关对 invoke/call 您的 Lambda 函数的权限 - 这对函数的功能没有影响。
如果这只是为了测试,您可以在身份和访问管理中找到该功能的 IAM 角色并附加 AmazonSNSFullAccess
策略 - 不要对任何类型的生产环境执行此操作,这授予了比必要更多的权限(在生产环境中,您将添加一个自定义策略,只允许对您的主题执行 sns:Publish
操作)。
现在您的函数有权向您的主题发布消息。
步骤 2 表示您需要编辑代码。如 documentation you linked 中所述导入 AWS SDK 是必要的,因为您希望您的代码与 AWS 服务交互 - 为此您需要 SDK。该文档中的其他步骤似乎是合理的,除了设置区域,如果您的主题与您的 lambda 函数位于同一 AWS 区域,则无需执行此操作。
一些额外的 observations/suggestions:
- 您的 CORS-Header
Access-Control-Allow-Origtin
中有错字 - 应该是 Origin。您也可以在 API 网关设置它,这样您的函数就不必处理它。
- 我建议您从 AWS Secrets Manager 或 Systems Manager Parameter Store 等获取数据库凭据,而不是将它们存储在代码中
- 通过在处理程序外部设置连接池,您可以让您的代码 re-use 现有 DB-Connections,干得好!
您可以看到,当 publish
没有完成他们的任务时,return response;
行将立即 运行 - 向 SNS 发布消息。因为 publish
、publishTextPromise.then
和 return
只是同步代码,所以只需一个滴答(~0,00..1 秒)即可完成。当处理程序函数调用 return
时,该函数将结束,这意味着所有正在执行的任务都将被取消(包括 publish
进程,该进程需要太多时间(~ < 1s and > one勾选完成)。
您将 async/await
语法与 promise 语法 (.then .catch) 混合使用,那么过程将不会如您所想(或想要)那样工作,我建议您尽可能使用 async/await
语法。
使用您的代码,我来宾 publish
任务不会影响响应,它只是尝试向 SNS 发布消息。
我的建议,改
publishTextPromise.then(
function (data) {
console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
console.log("MessageID is " + data.MessageId);
}).catch(
function (err) {
console.error(err, err.stack);
});
到
await publishTextPromise // wait until the task done
.then((data) => {
console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
console.log("MessageID is " + data.MessageId);
})
.catch((err) => {
console.error(err, err.stack);
});
await
关键字已添加,我更喜欢箭头函数语法
我有一个 lambda 函数,它通过 AWS lambda 函数处理 POST 请求。它处理 post 请求的主体并进行查询并 return 做出响应。
我的 LAMBDA 函数
const { Pool, Client } = require("pg");
const userName = 'blah';
const hostEndPoint = 'blah';
const databaseType = 'blahblah';
const pwd = 'pass pass';
const portNumber = 5432;
var AWS = require('aws-sdk');
const pool = new Pool({
user: userName,
host: hostEndPoint,
database: databaseType,
password: pwd,
port: portNumber
});
exports.handler = async (event) => {
let body = JSON.parse(event.body);
let name = body.name;
let money = body.money;
let todayDate = new Date();
var status = 0;
let text = 'INSERT INTO employee(name, date, salary) VALUES(, , ) RETURNING *';
let values = [name, todayDate, money];
var message = '';
var status = 0;
try {
const res = await pool.query(text, values)
message += 'successful'
status = 200;
} catch (err) {
message += 'unsuccessful'
if (err.code === '23505') {
status = 406;
}
}
var params = {
Message: 'Hello From Lambda', /* required */
TopicArn: 'arn:aws:sns:us-east-1:blahblahblah'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({ apiVersion: '2010-03-31' }).publish(params).promise();
publishTextPromise.then(
function (data) {
console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
console.log("MessageID is " + data.MessageId);
}).catch(
function (err) {
console.error(err, err.stack);
});
const response = {
statusCode: status,
body: JSON.stringify(message),
headers: {
"Access-Control-Allow-Origtin": '*'
}
};
return response;
};
我的 Lambda 资源策略 看起来像这样
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "blah-blah-blah-blah",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:blah-blah-blah-blah-blah",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:execute-api:us-east-1:blahblahblahblha:blah/*/POST/"
}
}
}
]
}
我还创建了一个 SNS 主题。如果我的状态是 200,我想向 SNS 主题发布消息。所以在我 return 响应之前。我想做这样的事情。
if (status === 200){
pubish some message to my sns topic
}
我是 aws 的新手,希望获得有关如何发布消息的指导。我觉得我很亲近。我确实遇到过这个 topic 但它让我感到困惑,因为我正在 lambda 函数中编辑代码,所以为什么我需要要求 aws-sdk 而且他们也没有谈论更改权限。
尝试以下建议的答案后更新了代码
我假设你的架构看起来像这样:
API-Gateway 接受请求并调用您向我们展示的 lambda 函数。 该 Lambda 函数连接到数据库并插入一条记录。您现在希望此 Lambda 函数也发布到 SNS 主题。
为此,您需要做两件事:
- 授予 Lambda 函数对 SNS 主题的权限
- 编写代码向主题发布消息
步骤 1 应该放在第一位,为此您需要编辑您的函数正在使用的 IAM 角色。 IAM 角色指定允许此 lambda 函数调用哪些 AWS 服务。您向我们展示的 Lambda 资源策略授予 API 网关对 invoke/call 您的 Lambda 函数的权限 - 这对函数的功能没有影响。
如果这只是为了测试,您可以在身份和访问管理中找到该功能的 IAM 角色并附加 AmazonSNSFullAccess
策略 - 不要对任何类型的生产环境执行此操作,这授予了比必要更多的权限(在生产环境中,您将添加一个自定义策略,只允许对您的主题执行 sns:Publish
操作)。
现在您的函数有权向您的主题发布消息。
步骤 2 表示您需要编辑代码。如 documentation you linked 中所述导入 AWS SDK 是必要的,因为您希望您的代码与 AWS 服务交互 - 为此您需要 SDK。该文档中的其他步骤似乎是合理的,除了设置区域,如果您的主题与您的 lambda 函数位于同一 AWS 区域,则无需执行此操作。
一些额外的 observations/suggestions:
- 您的 CORS-Header
Access-Control-Allow-Origtin
中有错字 - 应该是 Origin。您也可以在 API 网关设置它,这样您的函数就不必处理它。 - 我建议您从 AWS Secrets Manager 或 Systems Manager Parameter Store 等获取数据库凭据,而不是将它们存储在代码中
- 通过在处理程序外部设置连接池,您可以让您的代码 re-use 现有 DB-Connections,干得好!
您可以看到,当 publish
没有完成他们的任务时,return response;
行将立即 运行 - 向 SNS 发布消息。因为 publish
、publishTextPromise.then
和 return
只是同步代码,所以只需一个滴答(~0,00..1 秒)即可完成。当处理程序函数调用 return
时,该函数将结束,这意味着所有正在执行的任务都将被取消(包括 publish
进程,该进程需要太多时间(~ < 1s and > one勾选完成)。
您将 async/await
语法与 promise 语法 (.then .catch) 混合使用,那么过程将不会如您所想(或想要)那样工作,我建议您尽可能使用 async/await
语法。
使用您的代码,我来宾 publish
任务不会影响响应,它只是尝试向 SNS 发布消息。
我的建议,改
publishTextPromise.then(
function (data) {
console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
console.log("MessageID is " + data.MessageId);
}).catch(
function (err) {
console.error(err, err.stack);
});
到
await publishTextPromise // wait until the task done
.then((data) => {
console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
console.log("MessageID is " + data.MessageId);
})
.catch((err) => {
console.error(err, err.stack);
});
await
关键字已添加,我更喜欢箭头函数语法