4

I should start by saying I really know nothing about AWS, Lambda, or for that matter much about Python, so the likelihood of dumb mistakes is high.

I'm trying to create a system wherein a user POSTS a thing, the handler quickly passes them back a jobID, and then the user can revisit later to check on the process/get the result.

Basically:

def long_function(jobID, stuff): //dont know how to define this to be called asychronously
  //slow-running code
  //stuff the result in dynamoDB
  return

def lambda_handler(event, context):
    jobID = uuid.uuid4.hex
    stuff = event['stuff']
    long_function(jobID, stuff) //dont know how to write this call
    return jobID //should run before long_function completes

My understanding is that general python async stuff (which I'm also unfamiliar with) won't work, and I need to do a particular Lambda invocation. I'm failing to find a clear and simple way to do this (especially with python syntax)

1
  • Invoking a 2nd Lambda to do the real work might be a good option, and these 2 Lambdas can store the progress for a given Job ID in DynamoDB so you can implement a Lambda-based API to query the current status for Job X. Or your initial Lambda could trigger Step Functions to do the real work. Commented Aug 26, 2021 at 15:46

2 Answers 2

2

You are correct, the lambda function, once it returns, is done, and there is no way around that.

What you can do, also as you predicted, is launch another lambda function from within the first function (or a Batch job, or make a call to an EC2 instance for that matter).

You will need boto3 (it comes by default in all lambda Python environments) and you will need to give the lambda function the necessary IAM permissions to invoke another lambda function.

You can call either the original lambda function or another function. The code below assumes it is calling the same function.

The code itself is fairly simple:

import json
import boto3

def long_function(jobID, stuff):
    """Do something that takes a long time."""
    ...

def lambda_handler(event, context):
    # Unpack the event
    stuff = event["stuff"]
    is_long_func = event.get("is_long_func", False)

    # Route to the desired action.
    if not is_long_func:
        # Create a new job ID
        jobID = uuid.uuid4.hex

        # This is where the real business happens: invoke this
        # same lambda function with a different event.
        lam = boto3.client('lambda')
        lam.invoke_async(
            FunctionName="this-lambda-function-name",
            InvokeArgs=json.dumps({
                'jobID': jobID,
                'stuff': stuff,
                'is_long_func': True
            }).encode('utf-8')
        )
        return jobID

    else:
        # Run the long function.
        jobID = event["jobID"]
        long_function(jobID, stuff)
        return "OK"

If you need the result of the function, you can save the result of the function to s3 or similar and retrieve the contents with additional calls to the lambda function.

Sign up to request clarification or add additional context in comments.

1 Comment

This is a good answer, but invoke_async is now deprecated. As @Mark B points out in the other answer, one can use the InvocationType 'Event' when using invoke.
1

It's not going to be possible for a single Lambda invocation to generate the job ID and return it, and also keep processing afterwards.

You will need something like one Lambda function that generates a job ID, invokes another Lambda function asynchronously (using the event invocation type so it won't wait for that 2nd Lambda function to finish) and then returns the job ID.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.