发布于 2026-01-06 2 阅读
0

使用 Step Functions 无需轮询数据库即可安排电子邮件 DEV 的全球展示与讲述挑战赛,由 Mux 呈现:展示你的项目!

使用 Step Functions 无需轮询数据库即可安排电子邮件发送

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

发送电子邮件是网络应用程序的一项相当标准的功能。电子邮件服务提供商提供简单的 API,只需几行代码即可发送电子邮件。

但安排在未来某个时间发送这些提醒就麻烦多了。假设你想为新用户安排一个为期几天的引导流程,或者你需要发送用户在应用中创建的任务或事件的提醒。现在你必须:

  • ScheduledEmails在数据库中创建一个表,用于存储未来日期的消息。
  • 创建一个定时任务,轮询此表以查找待发送的电子邮件,并在邮件发送完毕后将其清除。
  • 维护运行 cron 作业的服务器。

这明明是一件简单得多的事情,却要花这么多时间去刮牦牛毛。

但还有一种更优雅的方法……

通过使用 AWS LambdaStep Functions,您可以获得以下解决方案:

  • 不需要数据库
  • 不涉及民意调查
  • 您只需为实际使用量付费。
  • 为您的应用程序提供一个简单的 API 调用来调用 Lambda 函数(该函数本身可以被视为一个微服务)。

如果你想直接查看完整代码库,请点击这里
如果你只想了解关键点,请继续跟随我的讲解,我将逐步介绍如何使用 Node.js 和 Serverless Framework 来实现这个功能。

📖相关内容:为什么无服务器新手应该使用部署框架

侧边栏:虽然我在这里使用了电子邮件,但这种方法可以应用于您的应用程序需要执行的任何未来计划任务。

准备工作

首先,安装 Serverless Framework
我们还将使用serverless-step-functions插件,以便轻松地在serverless.yml文件中配置 Step Functions。

配置 Step Functions 序列

发送电子邮件步骤函数状态机

序列中共有 2 个状态:

  1. WaitForDueDate:这只是一个等待步骤,它从输入对象中读取一个dueDate字段,并等待直到到达该时间,然后再继续到下一个状态。
  2. SendEmail:一个 Lambda 函数,用于调用 API 发送电子邮件。

配置如下:

# serverless.yml
# ...
stepFunctions:
  stateMachines:
    EmailSchedulingStateMachine:
      name: EmailSchedulingStateMachine
      definition:
        Comment: "Schedules an email to be sent at a future date"
        StartAt: WaitForDueDate
        States:
          WaitForDueDate:
            Type: Wait
            TimestampPath: "$.dueDate"
            Next: SendEmail
          SendEmail:
            Type: Task
            Resource: "arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${opt:stage}-SendEmail"
            End: true
Enter fullscreen mode Exit fullscreen mode

创建 SendEmail 函数

以下代码定义了 Lambda 函数的处理程序SendEmail,该处理程序由 Step Functions 配置中的 SendEmail 状态引用。该函数使用AWS SES发送电子邮件。

const AWS = require('aws-sdk');
const ses = new AWS.SES();
const { EMAIL_SENDER_ADDRESS } = process.env;

module.exports.handle = async (event) => {
    const result = await sendEmail(event.email);
    console.log('Sent email successfully', result);
    return result;
};

function sendEmail(email) {
    const params = {
        Destination: {
            ToAddresses: email.to,
        },
        Message: {
            Subject: {
                Data: email.subject,
            },
            Body: {
                Html: {
                    Data: email.htmlBody || email.textBody,
                },
                Text: {
                    Data: email.textBody || email.htmlBody,
                },
            },
        },
        Source: EMAIL_SENDER_ADDRESS,
    };
    return ses.sendEmail(params).promise();
}
Enter fullscreen mode Exit fullscreen mode

启动调度

现在,发送邮件的逻辑已经实现并连接到 Step Functions 状态机,我们需要一种方法从您的应用程序中启动该 Step Functions。这可以通过使用startExecutionStep Functions API 中的函数来实现。

// schedule-email.js
const AWS = require('aws-sdk');
const stepfunctions = new AWS.StepFunctions();

module.exports.scheduleEmail = async (dueDate, email) => {
    const stateMachineArn = process.env.STATEMACHINE_ARN;
    const result = await stepfunctions.startExecution({
        stateMachineArn,
        input: JSON.stringify({
            dueDate, email
        }),
    }).promise();
    console.log(`State machine ${stateMachineArn} executed successfully`, result);
    return result;
}

// ----------------------------------------------
// your-app-module.js
const scheduleEmail = require('./schedule-email');
const email = {
    to: ['test@example.com'],
    subject: 'MyApp Onboarding Day 1 - Setting up your project',
    textBody: 'TEXT body.\nsecond line.',
    htmlBody: '<strong>HTML</strong> body<br>second line.'
};
const dueDate = '2018-11-16T13:55:25.000Z';
const result = await scheduleEmail(dueDate, email);

// result :
// {
//     "executionArn": "arn:aws:states:eu-west-1:123456789:execution:EmailSchedulingStateMachine:84b1f498-ab4d-4f69-a635-ab1fa5199e16",
//     "startDate": "2018-11-16T16:19:23.560Z"
// }
Enter fullscreen mode Exit fullscreen mode

您需要更新应用程序运行所使用的 IAM 角色,以允许states:StartExecutionEmailSchedulingStateMachine状态机执行此操作。

如果我需要取消已安排的电子邮件怎么办?

startExecution调用返回一个对象,其中包含本次执行的唯一executionArn字符串。如果您需要取消电子邮件发送,可以存储此 ARN,然后stopExecution在执行进入 SendEmail 状态之前(假设执行尚未结束)将其传递给该函数以取消执行。

你自己试试看

如果您认为这对您有用,请克隆此仓库并自行部署。

您可以进行以下一些改进:


💌如果您喜欢这篇文章,可以订阅我的每周简讯,了解在 AWS 上构建无服务器 Web 应用的技巧
您可能还会喜欢:

原文发表于winterwindsoftware.com

文章来源:https://dev.to/paulswail/schedule-emails-without-polling-a-database-using-step-functions-1b10