2

I have a function in Lambda that executes for up to 30s depending on the inputs. That function is linked to an API gateway so I am able to call it through POST, unfortunatly the API Gateway is limited to 30s exaclty, so if my function runs for longer I get an "internal server error" back from my POST.

I see 2 solutions to this:

  • Create a "socket" rather then a simple POST which connects to the lambda function, not sure if this is even possible or how would this work.
  • Return a notification to api gateway before the lambda function is actually finished. This is acceptable for my use case, but I am not sure again how would this work.

The function is coded in Python3.6 I therefore have access to the event and context object.

4 Answers 4

6

Return a notification to api gateway before the lambda function is actually finished. This is acceptable for my use case, but I am not sure again how would this work.

Unfortunately, you will not be able to return a result until the Lambda is finished. Otherwise, AWS will interrupt execution of Lambda if you try to do it, for example, via multithreading.

I suggest you create the following system:

  1. API Gateway puts a request to Kinesis stream and returns a response of successfully putting. The response will contain SequenceNumber of the Kinesis Record. (How to do it)
  2. Lambda is invoked by Kinesis Stream Event, processes the request and saves that your job is done (or completed result) to DynamoDB with SequenceNumber as id.
  3. You invoke another API Gateway method and SequenceNumber to check the status of your job in DynamoDB (if necessary).

If you need just to run the Lambda without knowing of job result you can avoid using DynamoDB.

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

3 Comments

You could also simplify this and use two Lambdas, as in @cementblock's solution does below Also if you do this, the common RESTful pattern for long-running processes is something like: POST returns something a "201 accepted" with a Location header that you can use to poll for status with GET.
Well you could have a non-REST reqular labmba that does the real work. Call it asynchronously and return a task_id to the caller. Have caller expect a PUT of task id and result from the lambda later. Several variations such as putting result in SQS or as SNS message that fires whatever sends the result. Much simpler that adding Kinesis and probably cheaper. But really this sort of thing shows that everything should not be a lambda much less behind API Gateway in the first place.
In particular putting full web servers into a lambda via ECR under API Gateway is insanity.
5

statut approach is nice, but I'd like to give you an alternative: AWS step functions. Basically it does what statut's solution does but it might be more easy to deploy.

All you have to do is to create an AWS Step Functions state machine that has your lambda function as its only task. AWS Step functions intrinsically works asynchronously, and has methods to know the status and, eventually, the result. Check the docs for more info.

1 Comment

worked great for me with step functions, even if I didn't even knew them 2 hours ago... github.com/mavi888/stepfunction-triggers was pretty useful as a starting point
2

A very simple solution would be for your lambda function to just asynchronously invoke another lambda function and then return a result to API Gateway.

2 Comments

sure that sounds good but I am not sure how to connect 2 lambda functions. SNS ? Any link to another topic on this ?
use invoke method with Event as Invocation Type docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html
0

Here's a real example of executing one lambda function asynchronously from another lambda function:

import json
import boto3


def lambda_handler(event, context):
    
    payload = {}
    
    ##take the body of the request and convert to string    
    body = json.loads(event['body'])
    
    ##build new payload with body and anything else your function downstream needs
    payload['body'] = json.dumps(body)
    payload['httpMethod'] = 'POST'
    payloadStr = json.dumps(payload)
    
    client = boto3.client('lambda')
    client.invoke(
        FunctionName='container name',
        InvocationType="Event",
        Payload=payloadStr
    )


    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

In this example, the function invokes the other one and returns right away.

invoke documentation: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda.html#Lambda.Client.invoke

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.