370

I have 2 Lambda functions - one that produces a quote and one that turns a quote into an order. I'd like the Order lambda function to call the Quote function to regenerate the quote, rather than just receive it from an untrusted client.

I've looked everywhere I can think of - but can't see how I'd go about chaining or calling the functions...surely this exists!

Hank D
  • 5,654
  • 2
  • 20
  • 31
Silver
  • 4,061
  • 3
  • 13
  • 16
  • 2
    I'm reaching here, but why couldn't you depend on the AWS JavaScript SDK in the first Lambda function, create an [AWS.Lambda](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html) client and [invoke](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property) the second function? – devonlazarus Jul 30 '15 at 03:52
  • It's what I was going to try - but I wasn't entirely sure how to go about it, as there wasn't any examples of doing it from another Lambda function. – Silver Jul 30 '15 at 03:54
  • 1
    apparently you can also invoke a Lambda function through [HTTP](http://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html). – devonlazarus Jul 30 '15 at 03:59
  • 4
    and one more idea, you could [chain them through SNS](https://mobile.awsblog.com/post/Tx1VE917Z8J4UDY/Invoking-AWS-Lambda-functions-via-Amazon-SNS), which is probably the way I'd go as a more scalable strategy – devonlazarus Jul 30 '15 at 04:01
  • @devonlazarus it used to be chaining through SNS could provide a good async way of calling Lambda but now you can do this directly I believe. Do you still think it's a better approach going through SNS? Also, I assume SNS implies async, the example marked correct is a synchronous call so probably for these situations SNS should not be considered. Agree? – ken Jun 12 '16 at 17:14
  • @ken agree. if you're looking for 'synchronous' execution of Lambdas, then I would have one Lambda call the other directly. – devonlazarus Jun 13 '16 at 05:09
  • 8
    Another common alternatives not being mentioned here are Step Functions or SWF. – lebryant Nov 03 '17 at 19:46
  • Can I call the other Lambda if it resides inside a VPC and the caller lambda is outside that VPC? – Manthan Jamdagni Jun 02 '20 at 19:36

18 Answers18

408

I found a way using the aws-sdk.

var aws = require('aws-sdk');
var lambda = new aws.Lambda({
  region: 'us-west-2' //change to your region
});

lambda.invoke({
  FunctionName: 'name_of_your_lambda_function',
  Payload: JSON.stringify(event, null, 2) // pass params
}, function(error, data) {
  if (error) {
    context.done('error', error);
  }
  if(data.Payload){
   context.succeed(data.Payload)
  }
});

You can find the doc here: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html

Nicolas Grenié
  • 5,194
  • 1
  • 16
  • 32
  • 33
    Using SNS is probably the better approach, but this is the correct answer. – Silver Jul 31 '15 at 20:15
  • Were you able to get this work? I get security token errors when I try calling a lambda function from another lambda function. – Jay Nov 18 '15 at 23:27
  • I'm wondering about this too. My similar version isn't working and I suspect the reason is security related. – JohnAllen Dec 13 '15 at 09:23
  • 33
    i could be wrong, but I think because the invocation is synchronous that the first lambda waits for the second lambda to terminate, thus you will be accruing charges while both lambdas are running. using SNS, the first lambda should terminate and allow the second lambda to execute independently. – dev Jan 09 '16 at 19:50
  • 91
    I was able to get this to work thanks to the `InvocationType: 'Event'` parameter (add it after `FunctionName` and `Payload`). From the docs: _"You can optionally request asynchronous execution by specifying Event as the InvocationType."_ With async execution, the callback function will be reliably called, but without having to wait for the invoked lambda to finish executing. – Alessandro May 23 '16 at 15:56
  • 1
    Also, I didn't need to specify `region` when calling the `Lambda` constructor. The default seemed to work for me, though YMMV. – Alessandro May 23 '16 at 16:04
  • how do you handle credentials ? aren't needed when you are already in a Lmabda ? – alfonsodev May 28 '16 at 13:04
  • 1
    The documentation section that @Alessandro references is http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property – yegeniy Jan 17 '17 at 17:34
  • 27
    Note that the calling lambda function's role needs to include IAM policy `AWSLambdaRole`. Or, you can add the following statement object to your role's existing policy: '{ "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": ["*"] }` – Bob Arlof Feb 01 '17 at 22:23
  • @Silver from what I have read from docs SNS can deliver duplicate messages to its subscribers which means one has to add another layer of de-duplication logic. I have a lambda that puts tasks on a queue.. then on other side of this queue I have a cron lambda 'consumer' which reads messages from queue and then for each message invokes a 'worker' lambda directly (asynchronously using the 'Event' InvocationType) – 1977 Feb 20 '17 at 01:21
  • @1977 I think you're thinking of AWS, which is a queuing mechanism and can deliver the same message more than once, but guaranted, making it best suited to an idempotent service. SNS is a notification service and I think will deliver a only notification (Or potentially not at all) – Silver Feb 20 '17 at 06:26
  • @Silver you probably meant SQS (AWS' queues, which by default can potentially deliver a message multiple times). But it's a good point, I wonder if SNS notifications can also be delivered more than once. It's always good to make your jobs idempotent, but it's not always trivial. But agreed, write the logic to avoid duplication can add complexity. – Aldo 'xoen' Giambelluca May 12 '17 at 09:26
  • @BobArlof can you specify a more restricted resource? ie, tie the function's ability to invoke other functions down to a specific other function? – Phil Jan 29 '18 at 22:44
  • I have never gotten this to work a single time, it always times out { "errorMessage": "2018-08-02T23:34:27.503Z 866e0b24-96ac-11e8-975b-253c53738db4 Task timed out after 30.03 seconds" } – iamwhitebox Aug 02 '18 at 23:34
  • @iamwhitebox i think you have a blocking function in your code that hangs the lambda – Sebastien H. Aug 30 '18 at 08:01
  • 5
    Actually AWS released the StepFunctions which allows you to call multiple lambda without having to Invoke a lambda from another lambda, so that for ie. the first one doesn't "wait" for the second one to finish – Sebastien H. Aug 30 '18 at 08:02
  • How to pass payload in `x-www-urlencode` format if other lambda wants in this content-type – Prashant Tapase Apr 12 '19 at 07:09
  • I believe that this would cause the original lambda to block on the completion of the invoked (via API) lambda function. This doesn't seem like a good idea – pb2q Jun 27 '19 at 14:24
  • I realize it's been a long time, but couldn't AWS Step Functions make this work? – Danf Apr 21 '20 at 14:34
126

You should chain your Lambda functions via SNS. This approach provides good performance, latency and scalability for minimal effort.

Your first Lambda publishes messages to your SNS Topic and the second Lambda is subscribed to this topic. As soon as messages arrive in the topic, second Lambda gets executed with the message as it's input parameter.

See Invoking Lambda functions using Amazon SNS notifications.

You can also use this approach to Invoke cross-account Lambda functions via SNS.

adamkonrad
  • 5,867
  • 1
  • 28
  • 39
  • which is the better aproach SNS or Kinesis? I'm really in doubt, thanks. – Danilo Gomes Jun 27 '16 at 17:37
  • 2
    Kinesis may be a bit more complicated, but if you're looking at more robust solution, then it may be a good option for you. Also, SNS doesn't store the incoming events, Kinesis does. – adamkonrad Jun 27 '16 at 18:04
  • I added them to the post. – adamkonrad Jul 04 '16 at 03:00
  • 9
    "You should chain your Lambda functions via SNS" -- can you support this with evidence/links to docs? I see how both methods would work, I would be interested in seeing some opinions / definite statements on which one is the preferred one – Claude Nov 13 '16 at 09:33
  • It depends on your use case so there is no definitive answer. If you look at the number of upvotes on this, people successfully use it. – adamkonrad Nov 13 '16 at 15:04
  • 36
    This is a good idea if you need it to be asynchronous. But if your first lambda function *needs* the returned value from the second lambda, you have to chain the lambdas and have the first lambda function invoke the second lambda function directly. – Noel Llevares Dec 07 '16 at 04:23
  • 7
    I wouldn't recommend using SNS. You can just utilize the asynchronous invocation API for the lambda function-no reason to use SNS unless you want to notify multiple subscribers and not just trigger another lambda function. –  Mar 14 '17 at 16:42
  • 7
    Keep in mind that SNS does not have delivery guarantee so you'd might fire the message but it might not arrive. – Bart Van Remortele Apr 26 '17 at 13:58
  • 1
    Yes. When there's no subscriber it won't deliver the message, but that's a feature not a problem. – adamkonrad Apr 26 '17 at 14:33
  • Using this scenario also adds costs for SNS usage, which isn't the best practice imo – Sebastien H. Aug 30 '18 at 08:03
  • Of course, but you pay for all the benefits from the first paragraph. – adamkonrad Aug 30 '18 at 13:53
90

here's a sample code for python,

from boto3 import client as boto3_client
from datetime import datetime
import json

lambda_client = boto3_client('lambda')

def lambda_handler(event, context):
    msg = {"key":"new_invocation", "at": datetime.now()}
    invoke_response = lambda_client.invoke(FunctionName="another_lambda_",
                                           InvocationType='Event',
                                           Payload=json.dumps(msg))
    print(invoke_response)

Btw, you would need to add a policy like this to your lambda role as well

   {
        "Sid": "Stmt1234567890",
        "Effect": "Allow",
        "Action": [
            "lambda:InvokeFunction"
        ],
        "Resource": "*"
    }
blueskin
  • 8,713
  • 10
  • 67
  • 100
  • The documentation seems to suggest the payload must be JSON. Is it possible to send binary data? – mbatchkarov Jul 25 '17 at 19:22
  • 3
    I prefer this method also, but it's got one glitch. You'll need to convert the `datetime.now()` to a string (or handle it somehow). Otherwise, you get the error `datetime.datetime(2017, 9, 11, 14, 40, 53, 23834) is not JSON serializable` – John C Sep 11 '17 at 14:43
  • Is it possible to be more restrictive in the first lambda's role? Ie, to tie it down to invoking _specific_ functions, rather than any and all? – Phil Jan 29 '18 at 22:42
  • @Phil maybe the "Resource" field can be set to allow only a specific set of functions, I am not completely sure though – blueskin Jan 30 '18 at 03:24
  • Answer to my own comment, through personal experience is yes, you can. I'll propose an edit. – Phil Jan 30 '18 at 06:32
  • 2
    The `InvocationType` should be: `RequestResponse`. To get the response from the lambda that you are trying to invoke. – ambigus9 Sep 10 '19 at 19:03
  • And then if you have `InvocationType` to `RequestResponse` you should print `print(invoke_response['Payload'].read().decode())` to properly print the response message – Prageeth Jayathissa Jan 28 '20 at 15:55
38

Since this question was asked, Amazon has released Step Functions (https://aws.amazon.com/step-functions/).

One of the core principles behind AWS Lambda is that you can focus more on business logic and less on the application logic that ties it all together. Step functions allows you to orchestrate complex interactions between functions without having to write the code to do it.

dustinnoe
  • 545
  • 4
  • 7
15

This solution is done using boto3 and Python:

import boto3
import json

invokeLambda = boto3.client('lambda', region_name='eu-west-1')

def lambda_handler(event, context):
    invokeLambda.invoke(FunctionName = 'function_name', InvocationType = 'RequestResponse', Payload = json.dumps(event))

    return True
Eric Aya
  • 68,765
  • 33
  • 165
  • 232
Trilok Nagvenkar
  • 704
  • 7
  • 11
  • 4
    InvocationType Choose from the following options. RequestResponse (default) - Invoke the function synchronously. Keep the connection open until the function returns a response or times out. Event - Invoke the function asynchronously. Send events that fail multiple times to the function's dead-letter queue (if configured). DryRun - Validate parameter values and verify that the user or role has permission to invoke the function. – Trilok Nagvenkar Nov 21 '18 at 09:00
11

I was looking at cutting out SNS until I saw this in the Lambda client docs (Java version):

Client for accessing AWS Lambda. All service calls made using this client are blocking, and will not return until the service call completes.

So SNS has an obvious advantage: it's asynchronous. Your lambda won't wait for the subsequent lambda to complete.

Ben Iggulden
  • 349
  • 4
  • 7
  • 19
    InvocationType='Event' makes it async. http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property – Ankit Jan 20 '17 at 20:05
  • 3
    @Ankit that should be the selected answer, I was misled to believe using SNS was the only way to do an asynchronous invocation because nobody answered with this information. –  Mar 14 '17 at 16:43
  • @Ankit do you know of an example using InvocationType='Event' but from Java instead of JavaScript? There is a ton of Java documentation, but not nearly as many examples as JavaScript – Talador12 Feb 26 '18 at 21:16
  • SNS still adds costs for it's usage – Sebastien H. Aug 30 '18 at 08:04
  • 1
    @SebastienH. There is no cost for SNS invoking Lambda. https://aws.amazon.com/sns/pricing/ – fabdouglas Nov 26 '19 at 14:06
9

Amazon has introduced steps functions in AWS lambda in 2016. I think, now it's more convenient to use steps function as it's really easy to use them. You can build a state machine with two lambda functions as:

  • to produces a quote
  • turns a quote into an order

You can easily do that as below:

Here you can have first state for produces a quote and another to turns into order

{
  Comment: "Produce a quote and turns into an order",
  StartAt: "ProduceQuote",
  States: {
    ProduceQuote: {
      "Type": Task,
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ProduceQuote",
      "next": TurnsToOrder
    }
    TurnsToOrder: {
      Type: Task,
      Resource: "arn:aws:lambda:us-east-1:123456789012:function:ProduceQuote",
      end: true
    }
  }
}

Steps functions makes it really easy to write multiple lambda functions and run in sequence or in parallel. You can get more information about lambda steps functions here: Steps Functions

Sunil Kapil
  • 891
  • 11
  • 11
6

In java, we can do as follows :

AWSLambdaAsync awsLambdaAsync = AWSLambdaAsyncClientBuilder.standard().withRegion("us-east-1").build();

InvokeRequest invokeRequest = new InvokeRequest();
invokeRequest.withFunctionName("youLambdaFunctionNameToCall").withPayload(payload);

InvokeResult invokeResult = awsLambdaAsync.invoke(invokeRequest); 

Here, payload is your stringified java object which needs to be passed as Json object to another lambda in case you need to pass some information from calling lambda to called lambda.

Suyash
  • 515
  • 1
  • 6
  • 9
5

I was working with the answer provided by blueskin but I could not read the Payload response because the InvocationType='Event' is async, so I changed as InvocationType='RequestResponse' and now all works good.

antonio
  • 423
  • 5
  • 14
3

You might be able to make use of the Async.js Waterfall feature - see the bottom part of the big code chunk in Step 3 of this document for an example:

https://aws.amazon.com/blogs/compute/better-together-amazon-ecs-and-aws-lambda/

Mike
  • 536
  • 7
  • 20
2

You can invoke lambda function directly (at least via Java) by using AWSLambdaClient as described in the AWS' blog post.

Neil
  • 3,994
  • 3
  • 34
  • 36
2

I'm having the same problem but the Lambda function that I implement will insert an entry in DynamoDB, so my solution uses DynamoDB Triggers.

I make the DB invoke a Lambda function for every insert/update in the table, so this separates the implementation of two Lambda functions.

Documentation is here: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html

Here is a guided walkthrough: https://aws.amazon.com/blogs/aws/dynamodb-update-triggers-streams-lambda-cross-region-replication-app/

Lewen
  • 1,693
  • 2
  • 14
  • 16
2

Others pointed out to use SQS and Step Functions. But both these solutions add additional cost. Step Function state transitions are supposedly very expensive.

AWS lambda offers some retry logic. Where it tries something for 3 times. I am not sure if that is still valid when you trigger it use the API.

nnrales
  • 1,229
  • 1
  • 14
  • 21
2

Here is the python example of calling another lambda function and gets its response. There is two invocation type 'RequestResponse' and 'Event'. Use 'RequestResponse' if you want to get the response of lambda function and use 'Event' to invoke lambda function asynchronously. So both ways asynchronous and synchronous are available.

    lambda_response = lambda_client.invoke(
                FunctionName = lambda_name,
                InvocationType = 'RequestResponse',
                Payload = json.dumps(input)
                )
    resp_str = lambda_response['Payload'].read()
    response = json.loads(resp_str)
lalit gangwar
  • 211
  • 2
  • 6
1

Kind of a roundabout solution but I just call the API endpoint for my lambda functions when I need to chain them. This allows you to decide while coding if you want them to be asynchronous or not.

In case you don't want to setup a POST request you can just setup a simple GET request with a couple, or none at all, query string parameters for easy event passing.

-- Edit --

See: https://docs.aws.amazon.com/apigateway/api-reference/making-http-requests/

and: http://docs.aws.amazon.com/lambda/latest/dg/with-on-demand-https-example.html

Anselm
  • 1,301
  • 11
  • 22
  • 1
    this seems a lot less roundabout than SNS, but then i don't have much experience using SNS – Brandon Nov 14 '16 at 01:11
  • Can you share the code needed to call an API endpoint from within a lambda? – Glenn Aug 02 '17 at 20:20
  • @Glenn it's just an ajax request. Tag on your parameters that you need to as query parameters. See: https://docs.aws.amazon.com/apigateway/api-reference/making-http-requests/ and http://docs.aws.amazon.com/lambda/latest/dg/with-on-demand-https-example.html – Anselm Aug 03 '17 at 15:53
  • 4
    Another problem is that going through API Gateway is relatively expensive compared to calling another Lambda function. A 128MB function running for 100ms (the minimum) costs $0.21 per 1 million calls, whereas API Gateway costs $3.50 per 1 million. Obviously, if you're running for more time or you use more ram, you'd have to multiply the 21 cents, but still, $3.50 per million is really expensive. (These prices were effective as of August 2017) – Patrick Chu Aug 17 '17 at 17:57
0

You can trigger Lambda functions directly from other Lambda functions directly in an asynchronous manner.

https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-async-destinations

0

There are a lot of answers, but none is stressing that calling another lambda function is not recommended solution for synchronous calls and the one that you should be using is really Step Functions

Reasons why it is not recommended solution:

  • you are paying for both functions
  • your code is responsible for retrials

You can also use it for quite complex logic, such as parallel steps and catch failures. Every execution is also being logged out which makes debugging much simpler.

Black
  • 5,253
  • 3
  • 34
  • 43
-1

You can set AWS_REGION environment.

assert(process.env.AWS_REGION, 'Missing AWS_REGION env (eg. ap-northeast-1)');
const aws = require('aws-sdk');
const lambda = new aws.Lambda();
hojin
  • 607
  • 7
  • 14