如何每 24 小时从 Lambda 发送 SNS 消息?

How to Send SNS Message from Lambda every 24 Hours?

我是 Lambda 的新手,我正在尝试编写一个函数,每 24 小时通过 SNS 发送一封具有流动量的电子邮件。此 Lambda 函数由 IoT 规则触发,如果没有 24 小时限制,收件箱将被电子邮件淹没。在 CloudWatch 中,即使 email_sent 标志等于 1,也似乎正在发送电子邮件。所以这让我觉得我的圆括号和方括号的结构不正确?有人看到这段代码有什么问题吗?


var email_sent = 0;  //Flag to determine if the email has been sent in the last 24 hours
var starttime = new Date();  //Date & time when the script starts running

....

exports.handler = (event, context, callback) => {
 console.log('Start time.', starttime);
 console.log('Email Sent Flag.', email_sent);
 console.log('Received event:', event.my_volume, ' mL Volume');  //Fluid volume
 var miliseconds = new Date() - starttime;  //Calculate the time that has passed
 console.log('Miliseconds.', miliseconds);
 console.log(miliseconds/1000 + " Seconds.");
 if (miliseconds => 86,400,000) {    //Has 24 hours passed?
     email_sent = 0;   //set the email flag back to zero if the time has passed
 }
 // create/get topic
 if (email_sent == 0) {  //if the email flag is not set, setup topic and send the email
 createTopic('aws-iot-button-sns-topic', (err, topicArn) => {
     if (err) {
         return callback(err);
     }
     console.log(`Publishing to topic ${topicArn}`);
     // publish message
     const params = {
         Message: `The fluid level is low on your system: ${event.my_volume} mL.`,
         Subject: `Low Fluid Level Alert - Knight`,
         TopicArn: topicArn,
     };

     // result will go to function callback
     SNS.publish(params, callback);
     console.log('SNS Published.');
     email_sent = 1;  // after email is sent, reset the flag
     starttime = new Date();  // reset the starttime after the email is sent
 }
 );
} 
};

谢谢,

史蒂夫

所以我看到有两件事应该以不同的方式完成。

首先,你有这个:

createTopic('aws-iot-button-sns-topic', (err, topicArn) => {

现在您的函数正在创建不必要的主题,而没有删除它们,这是一个问题。您应该改为在外部创建 SNS 主题,并通过使用 Lambda 环境变量或 hard-coding SNS 主题 arn 在此处引用它。或者,首先检查具有该名称的主题是否已存在,如果存在则不要创建它。

其次,Lambda 不会 运行 超过 900 seconds (15 minutes),因此检查脚本是否已 运行 超过 24 小时是不可能的。

您应该做的是创建一个 CloudWatch event trigger that runs every 24 hours using cron。这样,您的 lambda 将 运行 每 24 小时恰好一次(或您配置的任何事件),并且在代码中您只需发送一次消息。然后就不需要检查现在几点或你已经发送了多少,因为你知道事件触发只发生一次,因此你的消息被发送一次并且你的 Lambda 立即结束执行。

Lambda 的本质是 short-lived 和无状态,因此请相应地设计您的服务:)

编辑:评论后,我更了解用例...在这种情况下,Lambda 由 IoT 执行,我会亲自将之前的执行时间存储在 SSM 参数存储或 DynamoDB 中,然后每当Lambda 被执行,我将获取值,检查是否已过 24 小时,如果已过则发送 SNS。您将必须这样做,因为 Lambda 不会知道最后一次执行时间是什么时候(并确保仅在成功的 SNS 发布调用上更新最后一次执行时间,您确定当天发送了一条消息)

这是另一种方法...

  • 将温度推送到 Amazon CloudWatch Metrics(见下文)
  • 创建一个 Amazon CloudWatch 警报 以在温度低于给定阈值时触发
  • 闹钟可以将消息发送到 Amazon SNS 主题
  • 人们可以订阅 SNS 主题以在发送消息时收到电子邮件

这只会在指标低于阈值时发送一条消息。不需要 Lambda(也许)。

我不太确定如何将 IoT 指标发送到 CloudWatch(我对 IoT 不是很熟悉)。这可能是相关的:Real-time metrics with AWS IoT Analytics and Amazon CloudWatch | The Internet of Things on AWS – Official Blog

或者,根据测量温度的系统,您可以将指标直接发送到 CloudWatch 而不是 IoT。

以下是 Amazon CloudWatch 发送到 Amazon SNS 的示例消息,该消息随后将发送给 SNS 主题的所有订阅者:

From: AWS Notifications <no-reply@sns.amazonaws.com>
Date: Mon, 13 May 2019 at 08:03
Subject: ALARM: "Fluid Level alert" in Asia Pacific (Sydney)

You are receiving this email because your Amazon CloudWatch Alarm "Fluid Level alert" in the Asia Pacific (Sydney) region has entered the ALARM state, because "Threshold Crossed: 1 datapoint [10.5 (12/05/19 21:58:00)] was less than or equal to the threshold (15.0)." at "Sunday 12 May, 2019 22:03:17 UTC".

View this alarm in the AWS Management Console:
https://console.aws.amazon.com/cloudwatch/home?region=ap-southeast-2#s=Alarms&alarm=Fluid%20Level%20alert

Alarm Details:
- Name:                       Fluid Level alert
- Description:                Fluid level has dropped below 15
- State Change:               INSUFFICIENT_DATA -> ALARM
- Reason for State Change:    Threshold Crossed: 1 datapoint [10.5 (12/05/19 21:58:00)] was less than or equal to the threshold (15.0).
- Timestamp:                  Sunday 12 May, 2019 22:03:17 UTC

Threshold:
- The alarm is in the ALARM state when the metric is LessThanOrEqualToThreshold 15.0 for 300 seconds. 

Monitored Metric:
- MetricNamespace:                     Vat12
- MetricName:                          FluidLevel
- Dimensions:                          
- Period:                              300 seconds
- Statistic:                           Average
- Unit:                                not specified


State Change Actions:
- OK: 
- ALARM: [arn:aws:sns:ap-southeast-2::alertme]
- INSUFFICIENT_DATA: 

引入 AWS IoT Events 服务解决了这个问题。

https://aws.amazon.com/iot-events/

我创建了一个检测器模型,该模型调用通过 SNS 主题发送电子邮件的 Lambda 函数。

在引入此服务之前,需要自定义开发才能通过电子邮件实现按时间顺序提醒。