Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS Cognito lambda triggers twice

I'm using an AWS Lambda function (using nodejs).

Once any request from APP to Cognito to signUp users. Then I have set the Pre sign-up trigger to validate the user's customer and check users custom attribute available in our database or not. If yes then return an error and else insert new records in DB and return the event to Cognito.

TimeoutInfo - 5 min.

It happens sometime in the request, not all the time. RequestId as different. (it will trigger 3 times sometime and most of the time twice)

Lambda trigger code as below.

users/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 = handler; users/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);
  }
}
like image 270
Mukesh S Avatar asked Jan 18 '19 07:01

Mukesh S


People also ask

Why is Lambda triggered multiple times?

Any event Executing Lambda several times is due to retry behavior of Lambda as specified in AWS document. Your code might raise an exception, time out, or run out of memory. The runtime executing your code might encounter an error and stop. You might run out concurrency and be throttled.

Can a Lambda have two triggers?

Your function can have multiple triggers. Each trigger acts as a client invoking your function independently. Each event that Lambda passes to your function has data from only one client or trigger.

How many triggers can be applied to a Lambda?

There is no limitations on number of triggers for a single lambda function. You can connect any number of queues to your lambda function. Or multiple event sources to a single lambda function.


1 Answers

This likely happens because of the Cognito-imposed execution timeout of 5 seconds for integration Lambdas - and it cannot be changed. Also note that the maximum amount of times that Cognito will (re-)attempt to call the function is 3 times.

In the Customizing User Pool Workflows with Lambda Triggers section it states that:

Important Amazon Cognito invokes Lambda functions synchronously. When called, your Lambda function must respond within 5 seconds. If it does not, Amazon Cognito retries the call. After 3 unsuccessful attempts, the function times out. This 5-second timeout value cannot be changed.

Therefore to reduce the execution time it would be worth to consider introducing caching where possible. Including database connections etc.

Do however note that you have little to no control over how often Lambdas are re-used versus re-launched and you will need to keep this in mind in terms of warm-up times.

like image 180
M Jensen Avatar answered Sep 18 '22 14:09

M Jensen