You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AWS Lambda中对非幂等API发起并发/并行请求?

解决方案:批量并发处理生日用户礼品卡任务

Node.js 并发实现方案

可以通过控制并发批次的方式,在单个Lambda内高效处理大量用户,避免超时问题。推荐使用p-limit库限制并发数,平衡数据库和邮件服务的压力。

核心代码示例

const pLimit = require('p-limit');
// 控制并发数,根据数据库和邮件服务的承载能力调整(比如20)
const concurrencyLimit = pLimit(20);

// Lambda 入口函数
exports.handler = async (event) => {
  let hasMoreUsers = true;
  const currentYear = new Date().getFullYear().toString();
  const currentMonth = (new Date().getMonth() + 1).toString().padStart(2, '0');

  while (hasMoreUsers) {
    // 1. 查询获取100位待处理的当月生日用户
    const users = await fetchEligibleUsers(currentYear, currentMonth);
    if (users.length === 0) {
      hasMoreUsers = false;
      break;
    }

    // 2. 并发处理用户任务
    const processingPromises = users.map(user => concurrencyLimit(async () => {
      try {
        // 为用户创建礼品卡并写入数据库
        await createAndSaveGiftCard(user, currentYear, currentMonth);
        // 发送生日礼品邮件
        await sendBirthdayGiftEmail(user);
      } catch (error) {
        console.error(`处理用户ID ${user.id} 失败:`, error);
        // 可选:将失败用户信息存入SQS队列,后续触发重试
      }
    }));

    // 等待当前批次所有任务完成
    await Promise.all(processingPromises);
  }

  return { statusCode: 200, body: '所有生日用户礼品卡任务处理完成' };
};

// 数据库查询:获取符合条件的用户
async function fetchEligibleUsers(year, month) {
  const sql = `
    SELECT u.id, u.first_name, u.last_name, u.email, u.date_of_birth
    FROM user u
    LEFT JOIN gift_card gc ON
        gc.scheduled_at >= ? AND gc.scheduled_at < ? AND
        gc.message = 'Happy birthday! from BURST' AND
        gc.status = 1 AND
        gc.recipient_email = u.email
    WHERE
        MONTH(u.date_of_birth) = ? AND
        u.email IS NOT NULL AND u.status = 10 AND
        gc.recipient_email IS NULL
    LIMIT 100
  `;
  // 替换为你的数据库客户端执行逻辑(如mysql2、pg等)
  // const [rows] = await dbConnection.execute(sql, [`${year}-01-01`, `${parseInt(year)+1}-01-01`, month]);
  // return rows;
  return []; // 示例返回空数组,实际替换为查询结果
}

// 创建并保存礼品卡到数据库
async function createAndSaveGiftCard(user, year, month) {
  // 实现礼品卡插入逻辑,生成礼品码等
  const giftCardSql = `
    INSERT INTO gift_card (recipient_email, message, status, scheduled_at, gift_code)
    VALUES (?, 'Happy birthday! from BURST', 1, ?, ?)
  `;
  const giftCode = generateUniqueGiftCode(); // 实现礼品码生成逻辑
  // await dbConnection.execute(giftCardSql, [user.email, `${year}-${month}-01`, giftCode]);
}

// 发送生日礼品邮件
async function sendBirthdayGiftEmail(user) {
  // 实现邮件发送逻辑(如使用AWS SES)
  // await sesClient.sendEmail({
  //   Destination: { ToAddresses: [user.email] },
  //   Message: { /* 邮件内容,包含礼品码 */ },
  //   Source: 'your-sender-email@example.com'
  // });
}

// 生成唯一礼品码
function generateUniqueGiftCode() {
  return Math.random().toString(36).substring(2, 10).toUpperCase();
}

关键注意事项

  • 并发数需根据数据库连接池大小、邮件服务发送限制调整,避免触发限流。
  • 失败任务建议存入SQS队列,配置单独的Lambda进行重试,避免丢失任务。
  • Lambda需配置足够的内存(如512MB)和超时时间(最大15分钟),确保单批次处理完成。

AWS 服务编排方案

如果用户量极大(十万级以上),单Lambda处理可能仍有瓶颈,推荐使用AWS原生服务组合实现分布式并发处理:

方案1:SQS + Lambda 分布式处理

  1. 触发Lambda:每月1号通过CloudWatch Events触发第一个Lambda,批量查询所有符合条件的用户,将每个用户的信息以消息形式发送到SQS标准队列。
  2. 消费Lambda:配置SQS触发第二个Lambda,每个Lambda实例处理1-5条用户消息(可在SQS触发器设置批量大小),自动并发扩容,处理礼品卡创建和邮件发送。
  3. 重试机制:SQS自动处理失败消息(可设置重试次数和延迟),最终将无法处理的消息存入死信队列,人工排查。

方案2:Step Functions 工作流编排

  1. 触发工作流:每月1号通过CloudWatch Events触发Step Functions状态机。
  2. 获取用户列表:调用Lambda查询100位用户。
  3. 并行处理:使用Step Functions的Map状态,并行处理每个用户的礼品卡创建和邮件发送任务(可设置并发数上限)。
  4. 循环迭代:处理完当前批次后,判断是否还有未处理用户,循环执行查询和处理步骤,直到所有用户处理完成。

SQL 查询优化建议

原SQL使用DATE_FORMAT函数会导致索引失效,降低查询效率,建议修改为范围查询和函数优化:

SELECT u.id, u.first_name, u.last_name, u.email, u.date_of_birth
FROM user u
LEFT JOIN gift_card gc ON
    -- 用范围查询替代DATE_FORMAT,利用scheduled_at索引
    gc.scheduled_at >= CONCAT(?,'-01-01') AND gc.scheduled_at < CONCAT(CAST(? AS UNSIGNED)+1,'-01-01') AND
    gc.message = 'Happy birthday! from BURST' AND
    gc.status = 1 AND
    gc.recipient_email = u.email
WHERE
    -- 直接提取月份,若user表有date_of_birth索引,可考虑新增计算字段birth_month
    MONTH(u.date_of_birth) = ? AND
    u.email IS NOT NULL AND u.status = 10 AND
    gc.recipient_email IS NULL
LIMIT 100
  • 建议为user.date_of_birth添加索引,或新增计算字段birth_month(存储1-12)并建立索引。
  • 为gift_card.scheduled_at和gift_card.recipient_email建立联合索引,加速关联查询。

内容的提问来源于stack exchange,提问作者Piyush Keshari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:45:56