Cosmin D
Cosmin D

Reputation: 729

Lambda execution quits before asynchronous event is finished

I encounter a weird behavior when I run a Lambda with Node v12 runtime. This lambda is triggered by a cloudwatch event rule.
It's purpose is to perform a certain operation, and then reschedule the rule to be invoked after a specific period (ex 5 minutes).

exports.handler= async function (event, context, callback) {
 console.info('Hello world');
 let nextValue = moment().add(5, 'minutes');
 let cronValue = `cron(${nextValue .minutes()} ${nextValue .hours()} 
 ${nextValue .date()} ${nextValue .month() + 1} ? ${nextValue .year()})`;
  let putRuleParams = {
        Name: RuleName, 
        Description: `Rechedule event`,
        ScheduleExpression: cronValue,
    };
    console.info(`Updating rule ${RuleName}. Params: `, putRuleParams);
    cloudwatchevents.putRule(putRuleParams, function(err, data) {
        if (err) {
            console.error('Error updating rule', err);
        } else {
            console.info('Successfully updated rule', data);
        }
    });
    console.info('After execution');
}

The output is the following

2020-01-31T14:19:07.749Z    97c23991-7710-4d98-accd-943b470d0875    INFO    Updating rule fiv- 
loadpartitions_rule. Params:  {
  Name: 'dummy_rule',
  State: 'DISABLED',
  Description: 'Scheduled on 31-01-2020 14:24 +00:00 to load partitions for generic_amount_tb 
  table.',
  ScheduleExpression: 'cron(24 14 31 1 ? 2020)'
}
2020-01-31T14:19:07.751Z    97c23991-7710-4d98-accd-943b470d0875    INFO    After execution
END RequestId: 97c23991-7710-4d98-accd-943b470d0875
REPORT RequestId: 97c23991-7710-4d98-accd-943b470d0875  Duration: 15639.87 ms   Billed Duration: 
15700 ms    Memory Size: 1536 MB    Max Memory Used: 101 MB Init Duration: 398.67 ms    

As you can see the update rule callback handler is not executed, as function execution ends before the event is completed. And there is no update on rule in AWS. How can I tell to Lambda to wait until the event is completed?

Upvotes: 3

Views: 4010

Answers (2)

Ashish Modi
Ashish Modi

Reputation: 7770

You are not waiting for your function to get completed. Use promise version and add await. Try this

exports.handler = async function (event, context, callback) {
  console.info("Hello world");
  const nextValue = moment().add(5, "minutes");
  const cronValue = `cron(${nextValue .minutes()} ${nextValue .hours()} 
  ${nextValue .date()} ${nextValue .month() + 1} ? ${nextValue .year()})`;
  const putRuleParams = {
    "Name": RuleName,
    "Description": "Rechedule event",
    "ScheduleExpression": cronValue
  };
  console.info(`Updating rule ${RuleName}. Params: `, putRuleParams);
  const response = await cloudwatchevents.putRule(putRuleParams).promise();
  return response;
  console.info("After execution");
};


you can use any of the aws sdk's method in a promise way by adding .promise() at the end.

Upvotes: 1

Jason Wadsworth
Jason Wadsworth

Reputation: 8887

You really have two options here.

  1. Remove the async from your function. That should keep the Lambda running until the event loop runs out or the lambda times out.
  2. Change your callback to be a promise and await it. You can just add .promise() to the end of the call, and the response to the call will be the data you'd put in your callback.

https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html

Upvotes: 4

Related Questions