首页 > 解决方案 > DynamoDb put 不会在 lambda 测试或 cron 中写入/保存到表,但在无服务器中有效

问题描述

我正在抓取一堆 API 并将数据保存到 dynamodb 表中。

serverless invoke local -f runAggregator在本地运行时一切正常。

然而,在我设置了 cron 之后,我注意到东西没有被保存到 Dynamodb 表中。

这是我的功能:

module.exports.runAggregator = async (event) => {
  await runModules({ saveJobs: true });

  return {
    statusCode: 200,
    body: JSON.stringify(
      {
        message: "Aggregate",
        input: event,
      },
      null,
      2
    ),
  };
};

runModules功能:

module.exports = async ({ saveJobs }) => {
  if (saveJobs) {
    const flushDb = await flushDynamoDbTable();
    console.log("Flushing Database: Complete");
    console.log(flushDb);
  }

  // pseudo code
  const allJobs = myLongArrayOfJobsFromApis

  const goodJobs = allJobs.filter((job) => {
    if (job.category) {
      if (!job.category.includes("Missing map for")) return job;
    }
  });

  // This runs absolutely fine locally...
  if (saveJobs) goodJobs.forEach(saveJob); // see below for function

  const badJobs = allJobs.filter((job) => {
    if (!job.category) return job; // no role found from API
    if (job.category.includes("Missing map for")) return job;
  });

  console.log("Total Jobs", allJobs.length);
  console.log("Good Jobs", goodJobs.length);
  console.log("Malformed Jobs", badJobs.length);

  return uniqBy(badJobs, "category");
};

保存作业功能

// saveJob.js
module.exports = (job) => {
  validateJob(job);

  dynamoDb
    .put({
      TableName: tableName,
      Item: job,
    })
    .promise();
};

当我在 lambda 控制台中运行“测试”时,我很困惑为什么这在本地工作得很好。我只是在 cron 运行后才发现表是空的。

标签: javascriptnode.jsamazon-dynamodbserverless

解决方案


saveJob执行异步操作(ddb.put().promise()),但您既不等待其完成也不返回承诺。

由于runModules函数中的 forEach 也不会等待任何内容,因此函数在调用 dynamodb 之前完成(因为 promise 与同步代码的工作方式),并且在 lambda 执行后进程被终止。

在本地,您不是在运行 lambda,而是在运行类似的东西。存在细微的差异,函数完成后发生的事情就是这些差异之一。所以它可能在本地工作,但它不会在实际的 lambda 上工作。

您需要做的是确保等待您对 dynamodb 的呼叫。就像是:

// saveJob.js
module.exports = (job) => {
  validateJob(job);

  return dynamoDb
    .put({
      TableName: tableName,
      Item: job,
    })
    .promise();
};

并在您的主要功能中:

...
if (saveJobs) await Promise.all(...goodJobs.map(job => saveJob(job)))

// or with a Promise lib such as bluebird:
if (saveJobs) await Promise.map(goodJobs, job => saveJob(job))
// (or Promise.each(...) if you need to make sure this happens in sequence and not in parallel)

注意:您可以/应该调用一次(或至少更少次)batchWriteItem操作,而不是多次调用 dynamodb.put,该操作可以在一次调用中写入多达 25 个项目,从而在此过程中节省相当多的延迟。


推荐阅读