btutal
btutal

Reputation: 135

NodeJS - Invoke Async Lambda from Another Async Lambda Function

I am trying to invoke async lambda function from another lambda function with NodeJS. At the end, I will have 3 lambda function. 1. Function will ask for user list 2. Function will ask details for each user 3. Create a record for that user in DB

First request is working fine, I can get user list but I don't see any sign that second lambda has been invoked.

'use strict';

const AWS = require("aws-sdk");
const rp = require('request-promise');

const lambda = new AWS.Lambda({
  region: "eu-central-1"
});

module.exports.getUserDetailsFromCrowd = async event => {
  console.log("Get User Details Function")
  var crowdUserDetailsOptions = {
    "method": "GET",
    "uri": event,
    'auth': {
      'user': process.env.user,
      'pass': process.env.pass,
      'sendImmediately': false
    },
    "json": true,
    "headers": {
      "Accept": "application/json"
    }
  }
  return rp(crowdUserDetailsOptions).then(function (result) {
    console.log(JSON.stringify(result))
  }).catch(function (err) {
    console.log(JSON.stringify(err))
  })
};

module.exports.getUserListFromCrowd = async event => {
  console.log("GetUserListFunction")
  var crowdUserGroupOptions = {
    "method": "GET",
    "uri": process.env.uri,
    'auth': {
      'user': process.env.user,
      'pass': process.env.pass,
      'sendImmediately': false
    },
    "json": true,
    "headers": {
      "Accept": "application/json"
    }
  };

  return rp(crowdUserGroupOptions)
    .then(function (body) {
      console.log("Request Sent")
      const userList = body;
      var userLinks = userList.users;
      for (var i = 0; i < userLinks.length; i++) {
        var requestLink = userLinks[i].link.href + "&expand=attributes"
        console.log("Request: " + i)
        console.log(requestLink)
        const params = {
          FunctionName: "applicationName-stageName-getUserDetailsFromCrowd",
          InvocationType: "Event",
          Payload: requestLink,
          LogType: "Tail",
        }
        console.log("Calling Lambda")
        lambda.invoke(params, function (err, data) {
          if (err) console.log(err, err.stack); // an error occurred
          else console.log(data); // successful response
        });
        console.log("Called Lambda")
      }
    })
    .catch(function (err) {
      console.log(JSON.stringify(err));
    });
};

I got the log below:

2019-11-08T08:38:29.892Z    1da97723-f792-408a-b6dd-24c7d1b343d4    INFO    Request: 9
2019-11-08T08:38:29.892Z    1da97723-f792-408a-b6dd-24c7d1b343d4    INFO    https://aaa.com/user/details
2019-11-08T08:38:29.892Z    1da97723-f792-408a-b6dd-24c7d1b343d4    INFO    Calling Lambda
2019-11-08T08:38:29.894Z    1da97723-f792-408a-b6dd-24c7d1b343d4    INFO    Called Lambda

I am at least expecting to see something in between "Calling Lambda" and "Called Lambda" but nothing happens. Also, I don't see any log on the console for second function that shows it has been invoked.

Upvotes: 1

Views: 2853

Answers (1)

James
James

Reputation: 82096

The Lambdas will be firing, the issue is you don't wait for the invocations to finish. Your Lambda is async, but you don't actually use await, and given the lambda.invoke is an I/O bound call there is nothing in your code that would force the Lambda to wait for each invocation to finish.

Here's a way you can queue up the internal calls and make your Lambda wait for the results:

module.exports.getUserListFromCrowd = async event => {
  console.log('GetUserListFunction')
  const crowdUserGroupOptions = {
    method: 'GET',
    uri: process.env.uri,
    auth: {
      user: process.env.user,
      pass: process.env.pass,
      sendImmediately: false
    },
    json: true,
    headers: {
      Accept: 'application/json'
    }
  };
  const { users } = await rp(crowdUserGroupOptions);
  console.log('Request Sent')
  const requests = users.map(u => 
    new Promise((resolve, reject) => {
      const url = `${u.link.href}&expand=attributes`;
      const params = {
        FunctionName: 'applicationName-stageName-getUserDetailsFromCrowd',
        InvocationType: 'Event',
        Payload: requestLink,
        LogType: 'Tail',
      }
      console.log('Calling Lambda');
      lambda.invoke(params, (err, data) => err ? reject(err) : resolve(data));
    })
  );
  console.log(`Waiting for ${requests.length} requests to finish...`);
  const results = await Promise.all(requests);
  console.log('Lambda results');
  results.forEach((x, i) => console.log(`Request ${i+1} returned ${x}`));
};

Upvotes: 2

Related Questions