6

I'm using Flask and Zappa to deploy to AWS Lambda, but one of my tasks takes more than 300 seconds to execute so the lambda shuts down.

I'd like to call another lambda before it happens to finish the work, is it possible to get the remaining time using Zappa?

Fernando Freitas Alves
  • 3,709
  • 3
  • 26
  • 45

1 Answers1

7

Below is the simple app I built

from flask import Flask, jsonify, request
import time
import traceback

app = Flask(__name__)

@app.route("/")
def index():
    return jsonify(traceback.format_stack())

if __name__ == "__main__":
   app.run()

And that gave me traceback

[
" File "/var/runtime/awslambda/bootstrap.py", line 534, in <module> main() ",
" File "/var/runtime/awslambda/bootstrap.py", line 529, in main handle_event_request(request_handler, invokeid, event_body, context_objs, invoked_function_arn) ",
" File "/var/runtime/awslambda/bootstrap.py", line 249, in handle_event_request result = request_handler(json_input, context) ",
" File "/var/task/handler.py", line 511, in lambda_handler return LambdaHandler.lambda_handler(event, context) ",
" File "/var/task/handler.py", line 242, in lambda_handler return handler.handler(event, context) ",
" File "/var/task/handler.py", line 454, in handler response = Response.from_app(self.wsgi_app, environ) ",
" File "/var/task/werkzeug/wrappers.py", line 903, in from_app return cls(*_run_wsgi_app(app, environ, buffered)) ",
" File "/var/task/werkzeug/test.py", line 884, in run_wsgi_app app_rv = app(environ, start_response) ",
" File "/var/task/zappa/middleware.py", line 70, in __call__ response = self.application(environ, encode_response) ",
" File "/var/task/flask/app.py", line 1997, in __call__ return self.wsgi_app(environ, start_response) ",
" File "/var/task/flask/app.py", line 1982, in wsgi_app response = self.full_dispatch_request() ",
" File "/var/task/flask/app.py", line 1612, in full_dispatch_request rv = self.dispatch_request() ",
" File "/var/task/flask/app.py", line 1598, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) ",
" File "/var/task/myapp.py", line 8, in index return jsonify(traceback.format_stack()) "
]

The traceback pointed me to

https://github.com/Miserlou/Zappa/blob/f7a785351450fa9115864c7dfe223660f5a99ae6/zappa/handler.py#L454

Just before that it has

# We are always on https on Lambda, so tell our wsgi app that.
environ['HTTPS'] = 'on'
environ['wsgi.url_scheme'] = 'https'
environ['lambda.context'] = context

These are filled in WSGI app environ for the request. This is accessible as flask.request.environ.get. So then I changed the code to

from flask import Flask, jsonify, request
import time
import traceback

app = Flask(__name__)

@app.route("/")
def index():
    context = request.environ.get('lambda.context', None)
    if context is not None:
       before = context.get_remaining_time_in_millis()
       time.sleep(1)
       after = context.get_remaining_time_in_millis()
       return "Time Before={}\nTime After={}".format(before, after)
    return jsonify(traceback.format_stack())

if __name__ == "__main__":
   app.run()

And the response was as expected

Time Before After

PS: Detailed the solution, so you understand how to find solution to such problems

Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
  • Hey thanks for pointing me to the `get_remaining_time_in_millis()` method, that's what I needed to know, One question, the Time Before is ~30 seconds, assuming this was when lambdas were limited to 5 mins (now it has a 15 minute limit), what happened to the other 4.5 mins? Was this a cold start? Even still, that seems like a long time. – Davos Nov 08 '18 at 01:24
  • Really nice solution, but unfortunately it doesn't seem to play nicely with Zappa's asynchronous tasks, since those use Asynchronous AWS Lambda triggers and so there's no flask environment :( – Movpasd Apr 22 '22 at 14:34