从错过的航班到任务:在 AWS 上构建 24 小时提醒服务

发布: (2025年11月30日 GMT+8 05:19)
4 min read
原文: Dev.to

Source: Dev.to

🛠️ 技术栈

  • 数据层: DynamoDB 表用于存储预约(NameDateTime)。
  • 计算层: AWS Lambda 扫描表,判断哪些预约需要提醒。
  • 通知层: Amazon SNS 发送电子邮件 / 短信通知。

步骤详解

1. 创建 DynamoDB 表

属性
表名Appointment
主键分区键 = Name(字符串)
属性Name – 例如 “Dentist Visit”
Date – ISO 格式字符串,例如 2025-12-29
Time – 可选,24 小时制 (HH:mm)

如需为每个用户发送通知,可额外添加属性(例如 UserEmail)。

2. 创建 SNS 主题并订阅

  1. 打开 Amazon SNSTopicsCreate topic
  2. 主题名称: AppointmentReminders(Standard)。
  3. 复制 Topic ARN —— 稍后在 Lambda 代码中使用。
  4. 添加订阅:
    • 协议: Email(或 SMS)。
    • 终端: 你的电子邮件地址(或手机号码)。
  5. 通过 AWS 发送的链接确认订阅。

3. 创建 Lambda 函数(Node.js)

配置

  • 运行时: Node.js 18.x
  • 处理程序: index.handler
  • 内存 / 超时: 128 MB,30 秒(可自行调整)

index.js

// index.js
const { DynamoDBClient, ScanCommand } = require("@aws-sdk/client-dynamodb");
const { SNSClient, PublishCommand } = require("@aws-sdk/client-sns");

// Environment variables (set in Lambda console)
const TABLE_NAME = process.env.APPOINTMENT_TABLE;
const SNS_TOPIC_ARN = process.env.SNS_TOPIC_ARN;

const ddb = new DynamoDBClient({});
const sns = new SNSClient({});

exports.handler = async () => {
  // 1️⃣ Scan the Appointment table
  const scanParams = {
    TableName: TABLE_NAME,
    ProjectionExpression: "Name, #d, #t, Email",
    ExpressionAttributeNames: {
      "#d": "Date",
      "#t": "Time"
    }
  };

  const data = await ddb.send(new ScanCommand(scanParams));

  // 2️⃣ Determine which items are within the next 24 h
  const now = new Date();
  const next24h = new Date(now.getTime() + 24 * 60 * 60 * 1000);

  const reminders = data.Items.filter(item => {
    const dateStr = item.Date.S;               // e.g. "2025-12-29"
    const timeStr = item.Time?.S || "00:00";   // optional, default midnight
    const apptDate = new Date(`${dateStr}T${timeStr}:00Z`);
    return apptDate > now && apptDate <= next24h;
  });

  // 3️⃣ Publish a reminder for each upcoming appointment
  for (const appt of reminders) {
    const message = `Reminder: ${appt.Name.S} on ${appt.Date.S} at ${appt.Time?.S || "00:00"}.`;
    const publishParams = {
      TopicArn: SNS_TOPIC_ARN,
      Message: message,
      Subject: "24‑hour Appointment Reminder",
      MessageAttributes: {
        "email": {
          DataType: "String",
          StringValue: appt.Email?.S || ""
        }
      }
    };
    await sns.send(new PublishCommand(publishParams));
  }

  return {
    statusCode: 200,
    body: `Sent ${reminders.length} reminder(s).`
  };
};

在 Lambda 控制台中设置的环境变量

变量
APPOINTMENT_TABLEAppointment
SNS_TOPIC_ARNAppointmentReminders 主题的 ARN

4. 为 Lambda 配置 IAM 权限

将以下内联策略(或托管策略)附加到 Lambda 执行角色,以授予所需权限:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:Scan",
        "dynamodb:Query",
        "dynamodb:GetItem"
      ],
      "Resource": "arn:aws:dynamodb:*:*:table/Appointment"
    },
    {
      "Effect": "Allow",
      "Action": "sns:Publish",
      "Resource": "arn:aws:sns:*:*:AppointmentReminders"
    }
  ]
}

5. 在 DynamoDB 中添加测试项

NameDateTimeEmail
Dentist Visit2025-12-2909:00your.email@example.com

可通过 DynamoDB 控制台或 AWS CLI 添加:

aws dynamodb put-item \
  --table-name Appointment \
  --item '{"Name":{"S":"Dentist Visit"},"Date":{"S":"2025-12-29"},"Time":{"S":"09:00"},"Email":{"S":"your.email@example.com"}}'

6. 测试 Lambda

  1. 在 Lambda 控制台点击 Test,创建一个简单事件(函数本身不使用负载)。
  2. 运行测试。
  3. 检查你的电子邮件(或短信)——应收到类似以下内容的消息:
Subject: 24‑hour Appointment Reminder
Message: Reminder: Dentist Visit on 2025-12-29 at 09:00.

如果收到了邮件,说明端到端流程已成功。

🚀 我的收获

  • 忘记很容易,系统不会。 一个小型的无服务器栈可以可靠地给你提前提醒。
  • 24 小时的提前时间 足以让人做好准备,又不会显得打扰。
  • 你不需要庞大的平台——只要一个 DynamoDB 表、一个 Lambda 函数、一个 SNS 主题以及一个定时触发器(如 CloudWatch Events / EventBridge)每天运行一次即可。
  • 完成此项目巩固了核心 DevOps / 云工程 技能:最小权限 IAM 策略、Lambda 开发、DynamoDB 数据建模以及 SNS 通知。

这就是完整的提醒服务——简单、低成本且高效。祝构建愉快!

Back to Blog

相关文章

阅读更多 »

AWS 数据库即将登陆 Vercel 市场

我们正在扩大与 AWS 的合作伙伴关系,以加快开发者使用 AWS 基础设施进行构建和扩展的速度。12 月 15 日,Aurora PostgreSQL,Amaz...

Terraform 项目:简单 EC2 + 安全组

项目结构 terraform-project/ │── main.tf │── variables.tf │── outputs.tf │── providers.tf │── terraform.tfvars │── modules/ │ └── ec2/ │ ├── main.tf │ …