AWS Cognito lambda 触发两次

Posted

技术标签:

【中文标题】AWS Cognito lambda 触发两次【英文标题】:AWS Cognito lambda triggers twice 【发布时间】:2019-06-12 10:46:59 【问题描述】:

我正在使用 AWS Lambda 函数(使用 nodejs)。

一旦 APP 向 Cognito 发出任何请求以注册用户。 然后我设置了 预注册触发器 来验证用户的客户并检查我们数据库中是否可用的用户自定义属性。如果是,则返回错误,否则在 DB 中插入新记录并将事件返回给 Cognito。

TimeoutInfo - 5 分钟。

它在请求中的某个时候发生,而不是一直发生。 RequestId 不同。 (有时会触发 3 次,大部分时间会触发 2 次)

Lambda 触发代码如下。

用户/index.js

const handler = async (event, context) => 
  log.info('createUserLambda:start');
  // immediately return once the call back is called to avoid
  // lambda time out because of any open db connections
  context.callbackWaitsForEmptyEventLoop = false;
  return await preUserCreate(event);
;

exports.handler = 处理程序; 用户/users.js

export const preUserCreate = async (event) => 
  log.info('preUserCreate:Start');
  let userAttributes = event.request.userAttributes;
  const currentDate = moment().utc().format('YYYY-MM-DD HH:mm:ss');
  try 
    let userParams = 
      'docStatus': 'VRF'
    ;
    let docParams = [
      'docNumber': userAttributes['custom:document_number'] ? userAttributes['custom:document_number'] : '',
      'createdDate': currentDate
    ];
    if (docParams.length && docParams[0].docNumber) 
      let documentExit = await getDocs(docParams[0].docNumber);
      if (documentExit.length) 
        log.info('preUserCreate:Error');
        throw new Error('Document number already exist.');;
      
    

    let documentRs = await insertDocument(docParams);
    userParams = 
      'did': documentRs[0].id,
      'id': event.userName,
      'createdDate': currentDate,
      'updatedDate': currentDate,
      ...userParams
    ;
    let userRs = await insertUser([userParams]);
    if (docParams.length && docParams[0].docNumber) 
      let resultData = await getUserAccountFromAPI(docParams[0].docNumber);
      if (resultData) 
        let foramattedData = await formattedAccountsData(resultData, userRs[0].id, documentRs[0].id);
        await insertUserAccounts(foramattedData);
      
    
    log.info('preUserCreate:Success');
    event.response = 
      'autoConfirmUser': false,
      'autoVerifyPhone': false,
      'autoVerifyEmail': false
    ;
    return event;
   catch (error) 
    log.info('preUserCreate:Error', error);
    throw (error);
  

【问题讨论】:

向我们展示 lambda 的触发器! 【参考方案1】:

这可能是因为 Cognito 对集成 Lambda 施加了 5 秒的执行超时 - 并且无法更改。另请注意,Cognito 将(重新)尝试调用该函数的最大次数为 3 次。

在Customizing User Pool Workflows with Lambda Triggers 部分中声明:

重要 Amazon Cognito 同步调用 Lambda 函数。什么时候 调用,您的 Lambda 函数必须在 5 秒内响应。如果确实如此 不是,Amazon Cognito 会重试调用。 3次尝试失败后, 函数超时。此 5 秒超时值无法更改。

因此,为了减少执行时间,值得考虑在可能的情况下引入缓存。包括数据库连接等。

但请注意,您几乎无法控制 Lambda 的重复使用频率和重新启动频率,您需要在预热时间方面牢记这一点。

【讨论】:

我相信 cognito 尝试执行 lambda 的次数是 4 倍。至少这是我注意到的,我总是在 cloudwatch 中得到 4 条记录 和我一样。我在触发器中启动了一个数据库创建事务,每次都得到 4 条记录。【参考方案2】:

您是否有可能在 VPC 中运行您的 lambda?我已经看到了在冷启动时在 VPC 中运行的 Cognito 触发器的类似行为。一旦 lambda 变热,问题就消失了

我的预感是 Cognito 内部有一个很短的超时时间来执行触发器,如果​​触发器没有及时回复,它会自动重试。

我们最终不得不向触发器添加逻辑来测试这种情况,这样我们就不会重复写入数据库。

【讨论】:

嘿@Brian,我们面临着完全相同的问题。你还记得你们使用的解决方法吗?还是谢谢 @quartaela 由于我们的 lambda 正在获取 Cognito 用户数据并将其写入 SQL 数据库,因此我们只是检查了数据是否尚未插入。 感谢布赖恩的回复。这是否意味着您的 Lambda 至少会被触发两次? Cognito 将从第一次调用中获得超时,但用户数据将在内部插入。 Cognito 将再次触发它,它将检查数据库并在 5 秒内返回有效响应 @quartaela 是的,基本上就是这样

以上是关于AWS Cognito lambda 触发两次的主要内容,如果未能解决你的问题,请参考以下文章

在 AWS Cognito 用户池中删除用户时触发 Lambda 函数

AWS cognito 用户迁移池触发器不适用于登录流程

AWS Cognito Post-Confirmation [已结束]

AWS Cognito 用户池的事件触发器对象

在 DotNet 中创建 AWS Cognito PreSignup Lambda

通过 AWS Lambda 和 Cognito 注册用户(无服务器架构)