April 25, 2024

The ContactSunny Blog

Tech from one dev to another

Invoke an AWS Lambda Function from another Lambda Function

4 min read

I recently discovered that you can’t invoke more than one Lambda function in AWS for an S3 event, with the same prefix and suffix (or just with the same suffix, which was the issue in my case). So I wanted a way to invoke one Lambda function from another Lambda function. If you’re feeling kind of lost, check out the problem statement in my Github project. That could possibly add some context to the problem. If you don’t want to go there, I’ll try to explain it here again.

The Problem and the Requirement

In one of our projects, we have a Lambda function which is invoked whenever a text file is uploaded to a particular S3 bucket. The Lambda function takes that file, does some processing on the data in that file, and then does something else which I don’t really remember anymore. Last week, we decided that we need to add some more processing to the data. But the problem is, the new processing logic will be used in other places too, where we don’t need the existing function. So we decided to follow the single responsibility principle and write a new Lambda function.

Now I did do that, tested it, and then deployed it to production. But when I was configuring the triggers, I discovered that I can’t trigger more than one Lambda function on an S3 bucket with the same prefix and suffix. Now because in both cases I needed to process the exact same text files in both the Lambdas, all the configuration parameters were the same, except the Lambda function. This was not going to work. So I had to figure out a way to invoke this new Lambda function from within the first Lambda function. And therefore, the Googling started. I didn’t know this was a very straight forward solution. It is super simple. Let’s see how to do it.

The Code

Before we begin, as the title suggests, our Lambda functions are written in Java 8. So this code snippet is for a Java 8 program.

Because our Lambda is triggered for every text file upload to S3, we’re extending the RequestHandler<S3Event, String> class in our code. The AWS Java SDK provides an easy way to handle events with a handleRequest() method, which gets the S3 event as an argument along with the context. You just override this method in your class and it is automatically called whenever the Lambda is triggered. The signature of the method is as follows:

@Override
public String handleRequest(S3Event s3Event, Context context) {
	// your code here
}

If your new Lambda is expecting any event or input, you have to provide that as a JSON string while invoking the Lambda function. Because I wrote this new Lambda function thinking that it will be invoked whenever a file is uploaded, I am expecting an S3 event as the input. So we need to construct that input as a JSON object. For this example, I’m not going to give the whole S3Event object, but I’ll only use an example:

String keyName = "path/to/upload/directory/fileName.txt";
String bucketName = "uploads";

JSONObject payloadObject = new JSONObject();
payloadObject.put("keyName", keyName);
payloadObject.put("bucketName", bucketName);

String payload = payloadObject.toString();

The string variable payload is the payload that we’ll send as the argument to our new Lambda. Next, we create an AWSLambda object, which is necessarily the Lambda client provided by the AWS Java SDK. Creating this is pretty simple:

AWSLambda client = AWSLambdaAsyncClient.builder().withRegion(DEFAULT_LAMBDA_REGION).build();

The AWS Java SDK also provides a very handy class to invoke Lambda functions, InvokeRequest. We now need to create an object of this class, configure the Lambda function name, and also specify the payload.

InvokeRequest request = new InvokeRequest();
request.withFunctionName(LAMBDA_FUNCTION_NAME).withPayload(payload);

When you do this, the AWS SDK constructs the ARN of the Lambda function using the region you provided earlier while creating the Lambda client (DEFAULT_LAMBDA_REGION), and the function name you provided while creating the InvokeRequest object (LAMBDA_FUNCTION_NAME). So make sure the Lambda you want to invoke is actually in the region you specified while creating the client.

Once this is done, the only thing pending is invoking the new Lambda function. At this point, that is just a method call away:

InvokeResult invoke = client.invoke(request);

And that’s pretty much it, you have invoked a Lambda function from another Lambda function. It’s that’s easy. If you want to see the complete function, here it is:

private void invokeLambda(String keyName, String bucketName) throws JSONException {

    JSONObject payloadObject = new JSONObject();
    payloadObject.put("keyName", keyName);
    payloadObject.put("bucketName", bucketName);

    String payload = payloadObject.toString();

    logger.info("Payload: " + payload);
    logger.info("Invoking Lambda: " + LAMBDA_FUNCTION_NAME);

    AWSLambda client = AWSLambdaAsyncClient.builder().withRegion(DEFAULT_LAMBDA_REGION).build();

    InvokeRequest request = new InvokeRequest();
    request.withFunctionName(LAMBDA_FUNCTION_NAME).withPayload(payload);
    InvokeResult invoke = client.invoke(request);
    logger.info("Result invoking " + LAMBDA_FUNCTION_NAME + ": " + invoke);
}

And if you want to checkout the complete working example project, head over to my Github project over here.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.