Reputation: 231
I need a user-request from a web app to call an AWS Chalice endpoint which triggers a long-running job. I can't let the user's browser wait for a response.
Chalice creates a REST API in API Gateway automatically, so this should be possible as it's not an HTTP API.
How to implement an endpoint in AWS Chalice which responds to the user immediately before executing the attached Lambda function?
I am aware of the InvocationType: Event
header which should allow for this, but this has no effect, the endpoint does not call the Lambda asynchronously (the client gets a response when the job completes 20-30 seconds later).
Here's what the endpoint in the Chalice app roughly looks like:
@app.route('/api-v1/runLongJob', methods=['PUT'])
def run_long_job():
# do some stuff that takes a long time here
return {'status_code': 200}
I have also set InvocationType
as a header in the Method request
section in the API Gateway console:
See this screenshot for what that looks like
An example of how I call this endpoint from Python with the InvocationType
header:
url = "https://----------.execute-api.xx-xxxx-x.amazonaws.com/api/v1-api/runLongJob"
data = {
'some parameter': 'some data'
}
headers = {
'Content-Type': 'application/json',
'InvocationType': 'Event'
}
r = requests.put(
url,
data=json.dumps(data),
headers=headers
)
How to create an asynchronous endpoint in a Chalice app?
Upvotes: 1
Views: 771
Reputation: 231
The solution is to use the .lambda_function
feature in Chalice along with the invocationType='Event'
parameter in the invocation call, like this:
import boto3
from chalice import Chalice
lambda_client = boto3.client('lambda')
app = Chalice(app_name='api')
LOG.setLevel(logging.INFO)
@app.route('/v1/lambdaTest')
def test_endpoint():
LOG.info(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
_ = lambda_client.invoke(
FunctionName="api-dev-testFunction",
InvocationType='Event',
Payload="{}"
)
LOG.info(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
return {'status_code': 200}
@app.lambda_function(name='testFunction')
def test_lambda_function(event, context):
LOG.info(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
time.sleep(20)
LOG.info(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
This generates two lambda functions, one for the API and one for the asynchronous task. When the API is called, the response is immediate, but the task takes 20 seconds to complete.
Note that I had to manually permit the API lambda to invoke the other, in the AWS console.
Upvotes: 2