Node.js 在不超过速率限制的情况下,尽可能快地通过SES发送电子邮件

Node.js 在不超过速率限制的情况下,尽可能快地通过SES发送电子邮件,node.js,email,aws-sdk,amazon-ses,rate-limiting,Node.js,Email,Aws Sdk,Amazon Ses,Rate Limiting,我目前正在使用SendGrid从许多serverless node.js Lambda函数发送电子邮件,并计划从SendGrid传输到SES(因为价格合理) SendGrid的速率限制如此之高,以至于通过一些lambda函数向同时使用for循环的用户发送电子邮件从来不会引起问题。但SES有较低的速率限制(在我的情况下为每秒50封电子邮件),并且会出现超过最大发送速率限制的错误 如何在不超过速率限制的情况下尽可能快地发送电子邮件 我目前的计划是通过多个lambda函数向SQS队列发送电子邮件请求,

我目前正在使用SendGrid从许多serverless node.js Lambda函数发送电子邮件,并计划从SendGrid传输到SES(因为价格合理)

SendGrid的速率限制如此之高,以至于通过一些lambda函数向同时使用for循环的用户发送电子邮件从来不会引起问题。但SES有较低的速率限制(在我的情况下为每秒50封电子邮件),并且会出现超过最大发送速率限制的错误

如何在不超过速率限制的情况下尽可能快地发送电子邮件


我目前的计划是通过多个lambda函数向SQS队列发送电子邮件请求,并通过1个lambda函数在不停止时间的情况下运行来接收SQS消息以发送电子邮件。但是我不知道如何控制向SES发送请求的速度。

以下方法可以保证在
阵列中所有邮件都包含x或更多元素时,您将有x并发调用

每次一个呼叫结束,它都会呼叫下一个

let continuoused=0
函数sendXeMailsAtime(包含所有邮件的阵列,最大值=50){
同时(持续<最大值){
进行中++
const params=prepareParams(包含所有邮件的数组.shift())
ses.sendEmail(参数,(错误,数据)=>{
if(err)console.log(err,err.stack);//发生错误
else console.log(数据);//响应成功
进行中--
如果(数组中的邮件长度均大于0){
SendXeMailsAtime(包含所有邮件的阵列,最大值)
}
});
}
}
功能准备图(来自阵列的一项,包含所有邮件){
//…在这里,您准备好参数并返回
}

解决方案1

我认为您可以使用CloudWatch创建一个计划事件,并每1秒或2秒触发一次事件,它将调用lambda函数。在lambda函数内部,仅从SQS检索流程50条消息,并结束lambda函数

解决方案2

但我看到您将此
运行而不停止时间

如果您想这样做,那么您必须设置一个时间计数器,从开始向SES发送电子邮件请求到发送50个请求

如果时差大于1秒,则处理下一组电子邮件

如果时差小于1秒,则等待剩余时间,然后处理下一组电子邮件

SES文档在此链接中讨论了相同的问题,并建议在代码中引入速率限制逻辑


当您使用node以便可以查看此速率限制器库时,您可以通过使用sleep()来实现这一点

我的结论 我决定创建两个SQS队列(A和B)。队列B用于触发电子邮件发送功能,队列A用于在等待队列中添加消息。因此,我只需要控制将消息从队列A移动到队列B的速度,这使一切变得简单

我考虑了以下几点

错误处理 起初,我考虑使用while循环通过一个Lambda函数发送许多电子邮件,但这使得错误处理变得困难。当速率限制超出错误或发生其他意外异常时,需要等待一段时间并重试,但可能会超过Lambda函数的超时时间

可伸缩性 通过单个Lambda函数在1秒内从SQS队列接收50条消息并向SES发送50个请求是可能的,但如果速率限制提高到300或500,则不可能在一秒钟内处理那么多请求。将消息从一个SQS队列移动到另一个SQS队列,以便在每封电子邮件中调用Lambda函数,这相对容易扩展

电子邮件优先级 需要立即发送带有验证码的注册确认电子邮件,但活动电子邮件可以延迟发送。使用两个SQS队列,我可以控制优先级

自动焊接系统成本 为每封电子邮件调用Lambda函数要比在一个Lambda函数中发送多封电子邮件花费更多的时间,但AWS为此付出的成本并不十分昂贵。如果向SES发送请求需要1秒,则使用128 MB内存执行Lambda需要花费0.000002083美元(N.Virginia地区)。1000封电子邮件只需0.02083美元,可以忽略。

您还可以使用将并发Lambda执行次数限制为50次。并将SQS的批处理大小设置为1消息

在无服务器框架中,这将类似于:

sendNotificationsMail:
处理程序:lib/send email/handler.handler
储备货币:50
活动:
-sqs:
地址:xxxxx
批量大小:1
这将确保不会同时运行超过50个Lambda实例


但随后又出现了一个新的问题——如果您的函数在SES中执行得太快,则速率受每秒请求的限制,而不是并发请求的限制。如果一个请求需要200毫秒,您的函数将在一秒钟的前200毫秒内并发发送50个请求,并在剩下的800毫秒内尝试发送更多请求,这将导致速率限制超出错误。节点内没有睡眠函数,因此我假设您指的是睡眠包?这不应该在生产中使用,因为它会锁定事件循环。在撰写本文时,CloudWatch事件的最小时间精度为一分钟。你不能将其配置为每分钟发射一次。我的情况与你完全相同。我想知道你如何处理你的功能,以发送电子邮件的SES最高速率限制。由于您使用的是SQS触发器,因此如果您没有注册确认电子邮件,则队列每秒只能从等待队列中发送N封邮件,但是,如果您有注册确认电子邮件突发,则发送到SES的邮件数量可能会超过速率限制。提前谢谢。@ArmandoRodríguezAcosta,这不是正确处理的,但这是工作
 async function init() {
      console.log(1);
      await sleep(10000);
    }