rev
rev

Reputation: 51

How to invoke lambda asynchronously from another lambda using serverless framework

I'm trying to build out an architecture in Serverless Framework where one Lambda calls another Lambda asynchronously, using the Node.js AWS SDK. I understand that when invoking asynchronously, the calling Lambda will not wait for the called Lambda to run and respond, but instead will get a response from AWS with the status of the invocation itself.

From what I've read, the way to call a Lambda asynchronously is to use the Lambda invoke() method with InvocationType: 'Event' in the params (as opposed to synchronous invocation with InvocationType: 'RequestResponse'). However, it doesn't seem to matter what I set as the InvocationType; the second Lambda always runs in full and returns its response to the first, just as if I had set InvocationType: 'RequestResponse'.

In my serverless.yml file, I have:

functions:
  receive_deltas:
    handler: src/record/delta_lambdas.receive
    vpc: ${self:custom.vpc}
    events:
      - http:
          method: post
          path: v1/deltas
  
  process_deltas:
    handler: src/record/delta_lambdas.process
    vpc: ${self:custom.vpc}

In my TypeScript handler, I have:

import { Lambda } from 'aws-sdk';

export const receive = async (event) => {
  const { recordIds } = JSON.parse(event.body);

  const lambda = new Lambda({
    region: 'us-west-2',
    endpoint: 'http://localhost:3003',
  });

  const params = {
    FunctionName: 'orgconfig-dev-process_deltas',
    InvocationType: 'Event',
    Payload: JSON.stringify({ recordIds }),
  };

  lambda.invoke(params, (err, data) => {
    if (err) {
      console.log(err);
      return failureResponse(err);
    } else {
      return parseResponse(data);
    }
  });
};

export const process = async (event) => {
  console.log('running process lambda');

  // process a bunch of stuff

  console.log('finished processing');
};

The first Lambda always waits for the second Lambda to run in its entirety, and eventually gets a response of { StatusCode: 200, Payload: '' }. I'm expecting a successful async invocation to return an immediate response with StatusCode: 202.

What am I missing?

Upvotes: 3

Views: 2888

Answers (2)

Svetlana Silina
Svetlana Silina

Reputation: 106

a configuration that's worked for them with Serverless Offline and async Lambda invocation, it might be worth posting here for future internauts

Just in case someone's looking for a working config ...

Try async: true for both (invoker and invoked) functions in serverless.yml

InvocationType should be "Event" in lambda.invoke parameters

iam role statements : lambda:InvokeAsync

FunctionName for offline invocation should come in the format serviceName-stage-functionName, so all together it looks like:

functions:
  invoker:
  handler: ...your-handler
   environment:
     your_Ref_to_offlineLamName: "${self:service}-${opt:stage, self:provider.stage}-invoked"
     events:
      - http:
          method: get
          path: ...yourpath
          async: true
   invoked:
     handler: ...somehandler
     events:
      - http:
          method: post
          path: ...somepath
          async: true

handler

let param = {
      FunctionName: process.env.IS_OFFLINE == "true" ? process.env.your_Ref_to_offlineLamName : "whatever",
      InvocationType: "Event",
      Payload: JSON.stringify({test:"TESTTEST"})
    };
   lambda.invoke(param).promise()

tested in node15. (based on https://www.serverless.com/plugins/serverless-offline#usage-with-invoke)

Upvotes: 0

rev
rev

Reputation: 51

What I was missing, it seems, was that the Serverless Offline plugin—or at least my configuration of it—does not emulate asynchronous lambda invocation in this way. (Note in my Lambda constructor I had a localhost endpoint giving away that it was offline.) Once I deployed to an AWS instance, it worked perfectly.

If anyone has a configuration that's worked for them with Serverless Offline and async Lambda invocation, it might be worth posting here for future internauts.

Upvotes: 2

Related Questions