将 Python 应用程序部署到 AWS Lambda 时出错

Error on deploying Python app to AWS Lambda

我构建了一个 Python-Tornado 应用程序,并尝试使用 zappa 将其部署到 AWS Lambda。但是,我收到一个错误 错误:警告!已部署的 lambda 的状态检查失败。对“/”的 GET 请求产生了 502 响应代码。

我的根文件夹内的文件夹结构是:

├── amortization.py
├── config.py
├── dmi-amort-dev-1557138776.zip
├── main.py
├── requirements.txt
├── venv
│   ├── bin
│  
└── zappa_settings.json

zappa deploy dev 给我:

Calling deploy for stage dev..
Downloading and installing dependencies..
- pandas==0.24.2: Using locally cached manylinux wheel
- numpy==1.16.3: Using locally cached manylinux wheel
- sqlite==python3: Using precompiled lambda package
Packaging project as zip.
Uploading dmi-amort-dev-1557143681.zip (30.8MiB)..
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 32.3M/32.3M [00:19<00:00, 1.94MB/s]
Scheduling..
Scheduled dmi-amort-dev-zappa-keep-warm-handler.keep_warm_callback with expression rate(4 minutes)!
Uploading dmi-amort-dev-template-1557143718.json (1.5KiB)..
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.56K/1.56K [00:00<00:00, 10.6KB/s]
Waiting for stack dmi-amort-dev to create (this can take a bit)..
75%|█████████████████████████████████████████████████████████████████████████████████████████████████████▎                                 | 3/4 [00:09<00:04,  5.00s/res]
Deploying API Gateway..
Error: Warning! Status check on the deployed lambda failed. A GET request to '/' yielded a 502 response code.

zappa tail 给我

Traceback (most recent call last):
File "/var/task/handler.py", line 602, in lambda_handler
return LambdaHandler.lambda_handler(event, context)
File "/var/task/handler.py", line 245, in lambda_handler
handler = cls()
File "/var/task/handler.py", line 142, in __init__
wsgi_app_function = getattr(self.app_module, self.settings.APP_FUNCTION)
AttributeError: module 'main' has no attribute 'app'

zappa_settings.json:

{
    "dev": {
        "app_function": "main.app",
        "aws_region": "ap-south-1",
        "profile_name": "default",
        "project_name": "dmi-amort",
        "runtime": "python3.6",
        "s3_bucket": "zappa-mekp457ye",
        "manage_roles": false,
        "role_name": "lambda-role",
    }
}

main.py:

import tornado.web
from tornado.ioloop import IOLoop
from tornado.web import MissingArgumentError
from config import get_arguments
from amortization import get_amort_schedule

class MainHandler(tornado.web.RequestHandler):
    def prepare(self):
        """Checking if all the required parameters are present."""
        if self.request.method != 'POST':
            self.write_error(status_code=405, message="Method not allowed")
            return

        self.parameters = dict()
        for key in get_arguments():
            try:
                self.parameters[key] = self.get_argument(key)
            except MissingArgumentError:
                self.write_error(status_code=400,
                                message="Missing Argument(s)")
                return

        # checking if 'label' is provided
        if 'label' in self.request.arguments.keys():
            self.parameters['label'] = self.get_argument('label')
        # Set up response dictionary.
        self.response = dict()

    def get(self, *args, **kwargs):
        self.write_error(status_code=405, message="Method not allowed")

    def post(self, *args, **kwargs):
        """Executes the main logic part."""
        self.response = get_amort_schedule(self.parameters)
        self.write_json()

    def set_default_headers(self):
        """Sets content-type as 'application/json' for response as JSON."""
        self.set_header('Content-Type', 'application/json')

    def write_error(self, status_code, **kwargs):
        """Invokes when error occurs in processing the request."""
        if 'message' not in kwargs:
            if status_code == 405:
                kwargs['message'] = 'Invalid HTTP method.'
            else:
                kwargs['message'] = 'Unknown error.'
        kwargs["error"] = True
        self.set_status(status_code=status_code)
        self.response = dict(kwargs)
        self.write_json()

    def write_json(self):
        """Responsible for writing the response."""
        if "status" in self.response:
            self.set_status(self.response.get("status"))
        self.set_default_headers()
        self.write(self.response)
        self.finish()


def main():
    app = tornado.web.Application([
        (r'/', MainHandler),
    ], debug=True)
    # server = HTTPServer(app)
    # server.bind(8888)
    # server.start(0)
    app.listen()
    # app.run(host='0.0.0.0')
    IOLoop.current().start()


if __name__ == '__main__':
    main()

这里有什么错误,我该如何解决?

看起来部署成功了,但是当 Zappa 检查代码是否正常工作时,return 代码是 502,这表明 lambda 函数失败 运行 在 lambda 环境中。

查看日志,关键行是:

AttributeError: module 'main' has no attribute 'app'

确实如此,如果我们查看您的代码,您绝不会在 main.py 中公开名为 app 的属性。

我没有使用 Tornado 的经验,但我怀疑如果将 app 的声明移出 main() 函数并移至根范围内,那么处理程序应该会成功。

例如:

        # rest of the file...
        self.finish()

app = tornado.web.Application([
    (r'/', MainHandler),
], debug=True)
app.listen()

def main():
    IOLoop.current().start()

if __name__ == '__main__':
    main()