简体   繁体   English

为什么在部署本地运行良好的 Flask 应用程序时 Heroku 崩溃(代码=H10)?

[英]Why did Heroku crash (code=H10) when deploying my Flask app that runs well locally?

I was trying to deploy an XGBoost model with Flask and Heroku and followed this tutorial on Medium.我正在尝试使用 Flask 和 Heroku 部署 XGBoost model 并在 Medium 上遵循本教程 After getting the app successfully running on my local machine, I couldn't deploy it on Heroku without incurring "Application Error".在我的本地计算机上成功运行该应用程序后,我无法在 Heroku 上部署它而不会引发“应用程序错误”。 (I tried to deploy the tutorial author's code and ran into exactly the same issue.) (我尝试部署教程作者的代码并遇到了完全相同的问题。)

Below is code in all relevant files and the error message.以下是所有相关文件中的代码和错误消息。 Would appreciate it if anyone has a clue about how to solve this issue?如果有人知道如何解决此问题,将不胜感激?

Code in app.py : app.py中的代码:

import pickle
import pandas as pd
import flask 

# Load two pre-trained models
with open(f"model/classifier.pkl", "rb") as f:
    model = pickle.load(f)

with open(f"model/age_scaler.pkl", "rb") as f:
    scaler = pickle.load(f)

# Initialize the Flask app
app = flask.Flask(__name__, template_folder="templates")

# Set up the main route
@app.route("/", methods=["GET", "POST"])
def main():
    if flask.request.method == "GET":
        # Just render the initial form, to get input
        return flask.render_template("main.html")

    if flask.request.method == "POST":
        # Extract the input
        age = flask.request.form["age"]
        sex = flask.request.form["sex"]
        preconition = flask.request.form["chronic_disease_binary"]
        hypertension = flask.request.form["hypertension"]
        diabetes = flask.request.form["diabetes"]
        heart = flask.request.form["heart"]
        fever = flask.request.form["fever"]
        cough = flask.request.form["cough"]
        fatigue = flask.request.form["fatigue"]
        sore_throat = flask.request.form["sore_throat"]

        # Make DataFrame for model
        input_variables = pd.DataFrame(
            [
                [
                    scaler.transform([[age]])[0][0],
                    sex,
                    preconition,
                    hypertension,
                    diabetes,
                    heart,
                    fever,
                    cough,
                    fatigue,
                    sore_throat,
                ]
            ],
            columns=[
                "age",
                "sex",
                "chronic_disease_binary",
                "hypertension",
                "diabetes",
                "heart",
                "fever",
                "cough",
                "fatigue",
                "sore throat",
            ],
            dtype=float,
            index=["input"],
        )

        # Get the model's prediction
        prediction = model.predict_proba(input_variables)[0][1]

        # Render the form again, but add in the prediction and remind user
        # of the values they input before
        return flask.render_template(
            "main.html",
            original_input={
                "Age": age,
                "Sex": sex,
                "Precondition": preconition,
                "Hypertension": hypertension,
                "Diabetes": diabetes,
                "Heart disease": heart,
                "Fever": fever,
                "Cough": cough,
                "Fatigue": fatigue,
                "Sore throat": sore_throat,
            },
            result= "{} %".format(round(float(prediction), 2) * 100)
        )


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

Code in Procfile : Procfile中的代码:

web: gunicorn app:app

Code in requirements.txt requirements.txt中的代码

flask
pandas
gunicorn
xgboost
sklearn

heroku logs : heroku logs

(base) MacBook-Pro-2:covid19-app apple$ heroku logs --tail
2020-04-04T08:18:12.896599+00:00 app[web.1]: [bt] (5) /app/.heroku/python/lib/python3.6/lib-dynload/_ctypes.cpython-36m-x86_64-linux-gnu.so(_ctypes_callproc+0x4cd) [0x7f06a8e52e1d]
2020-04-04T08:18:12.896599+00:00 app[web.1]: [bt] (6) /app/.heroku/python/lib/python3.6/lib-dynload/_ctypes.cpython-36m-x86_64-linux-gnu.so(+0x8ba7) [0x7f06a8e49ba7]
2020-04-04T08:18:12.896599+00:00 app[web.1]: [bt] (7) /app/.heroku/python/bin/python(_PyObject_FastCallDict+0xb3) [0x55d8fdde2bc3]
2020-04-04T08:18:12.896600+00:00 app[web.1]: [bt] (8) /app/.heroku/python/bin/python(+0x1890f0) [0x55d8fdedc0f0]
2020-04-04T08:18:12.896600+00:00 app[web.1]: 
2020-04-04T08:18:12.896607+00:00 app[web.1]: 
2020-04-04T08:18:12.896917+00:00 app[web.1]: [2020-04-04 08:18:12 +0000] [10] [ERROR] Exception in worker process
2020-04-04T08:18:12.896918+00:00 app[web.1]: Traceback (most recent call last):
2020-04-04T08:18:12.896918+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
2020-04-04T08:18:12.896919+00:00 app[web.1]: worker.init_process()
2020-04-04T08:18:12.896919+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 119, in init_process
2020-04-04T08:18:12.896920+00:00 app[web.1]: self.load_wsgi()
2020-04-04T08:18:12.896920+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
2020-04-04T08:18:12.896920+00:00 app[web.1]: self.wsgi = self.app.wsgi()
2020-04-04T08:18:12.896921+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 67, in wsgi
2020-04-04T08:18:12.896921+00:00 app[web.1]: self.callable = self.load()
2020-04-04T08:18:12.896922+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
2020-04-04T08:18:12.896922+00:00 app[web.1]: return self.load_wsgiapp()
2020-04-04T08:18:12.896922+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
2020-04-04T08:18:12.896923+00:00 app[web.1]: return util.import_app(self.app_uri)
2020-04-04T08:18:12.896923+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/util.py", line 358, in import_app
2020-04-04T08:18:12.896923+00:00 app[web.1]: mod = importlib.import_module(module)
2020-04-04T08:18:12.896924+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/importlib/__init__.py", line 126, in import_module
2020-04-04T08:18:12.896924+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2020-04-04T08:18:12.896924+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 994, in _gcd_import
2020-04-04T08:18:12.896925+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 971, in _find_and_load
2020-04-04T08:18:12.896925+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
2020-04-04T08:18:12.896925+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
2020-04-04T08:18:12.896926+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 678, in exec_module
2020-04-04T08:18:12.896926+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
2020-04-04T08:18:12.896926+00:00 app[web.1]: File "/app/app.py", line 7, in <module>
2020-04-04T08:18:12.896927+00:00 app[web.1]: model = pickle.load(f)
2020-04-04T08:18:12.896927+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/xgboost/core.py", line 1094, in __setstate__
2020-04-04T08:18:12.896927+00:00 app[web.1]: _LIB.XGBoosterUnserializeFromBuffer(handle, ptr, length))
2020-04-04T08:18:12.896928+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/xgboost/core.py", line 189, in _check_call
2020-04-04T08:18:12.896928+00:00 app[web.1]: raise XGBoostError(py_str(_LIB.XGBGetLastError()))
2020-04-04T08:18:12.896929+00:00 app[web.1]: xgboost.core.XGBoostError: [08:18:12] /workspace/src/learner.cc:682: Check failed: header == serialisation_header_:
2020-04-04T08:18:12.896956+00:00 app[web.1]: 
2020-04-04T08:18:12.896956+00:00 app[web.1]: If you are loading a serialized model (like pickle in Python) generated by older
2020-04-04T08:18:12.896956+00:00 app[web.1]: XGBoost, please export the model by calling `Booster.save_model` from that version
2020-04-04T08:18:12.896957+00:00 app[web.1]: first, then load it back in current version.  There's a simple script for helping
2020-04-04T08:18:12.896957+00:00 app[web.1]: the process. See:
2020-04-04T08:18:12.896957+00:00 app[web.1]: 
2020-04-04T08:18:12.896957+00:00 app[web.1]: https://xgboost.readthedocs.io/en/latest/tutorials/saving_model.html
2020-04-04T08:18:12.896958+00:00 app[web.1]: 
2020-04-04T08:18:12.896958+00:00 app[web.1]: for reference to the script, and more details about differences between saving model and
2020-04-04T08:18:12.896958+00:00 app[web.1]: serializing.
2020-04-04T08:18:12.896958+00:00 app[web.1]: 
2020-04-04T08:18:12.896958+00:00 app[web.1]: 
2020-04-04T08:18:12.896959+00:00 app[web.1]: Stack trace:
2020-04-04T08:18:12.896959+00:00 app[web.1]: [bt] (0) /app/.heroku/python/lib/python3.6/site-packages/xgboost/./lib/libxgboost.so(dmlc::LogMessageFatal::~LogMessageFatal()+0x54) [0x7f066f73b614]
2020-04-04T08:18:12.896959+00:00 app[web.1]: [bt] (1) /app/.heroku/python/lib/python3.6/site-packages/xgboost/./lib/libxgboost.so(xgboost::LearnerImpl::Load(dmlc::Stream*)+0x661) [0x7f066f82dc71]
2020-04-04T08:18:12.896960+00:00 app[web.1]: [bt] (2) /app/.heroku/python/lib/python3.6/site-packages/xgboost/./lib/libxgboost.so(XGBoosterUnserializeFromBuffer+0x4e) [0x7f066f72b8be]
2020-04-04T08:18:12.896960+00:00 app[web.1]: [bt] (3) /usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call_unix64+0x4c) [0x7f06a8c3edae]
2020-04-04T08:18:12.896961+00:00 app[web.1]: [bt] (4) /usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call+0x22f) [0x7f06a8c3e71f]
2020-04-04T08:18:12.896961+00:00 app[web.1]: [bt] (5) /app/.heroku/python/lib/python3.6/lib-dynload/_ctypes.cpython-36m-x86_64-linux-gnu.so(_ctypes_callproc+0x4cd) [0x7f06a8e52e1d]
2020-04-04T08:18:12.896961+00:00 app[web.1]: [bt] (6) /app/.heroku/python/lib/python3.6/lib-dynload/_ctypes.cpython-36m-x86_64-linux-gnu.so(+0x8ba7) [0x7f06a8e49ba7]
2020-04-04T08:18:12.896961+00:00 app[web.1]: [bt] (7) /app/.heroku/python/bin/python(_PyObject_FastCallDict+0xb3) [0x55d8fdde2bc3]
2020-04-04T08:18:12.896962+00:00 app[web.1]: [bt] (8) /app/.heroku/python/bin/python(+0x1890f0) [0x55d8fdedc0f0]
2020-04-04T08:18:12.896962+00:00 app[web.1]: 
2020-04-04T08:18:12.896966+00:00 app[web.1]: 
2020-04-04T08:18:12.897433+00:00 app[web.1]: [2020-04-04 08:18:12 +0000] [11] [INFO] Worker exiting (pid: 11)
2020-04-04T08:18:12.898007+00:00 app[web.1]: [2020-04-04 08:18:12 +0000] [10] [INFO] Worker exiting (pid: 10)
2020-04-04T08:18:13.038533+00:00 app[web.1]: Traceback (most recent call last):
2020-04-04T08:18:13.038540+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 209, in run
2020-04-04T08:18:13.038884+00:00 app[web.1]: self.sleep()
2020-04-04T08:18:13.038887+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 357, in sleep
2020-04-04T08:18:13.039274+00:00 app[web.1]: ready = select.select([self.PIPE[0]], [], [], 1.0)
2020-04-04T08:18:13.039295+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 242, in handle_chld
2020-04-04T08:18:13.039585+00:00 app[web.1]: self.reap_workers()
2020-04-04T08:18:13.039616+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 525, in reap_workers
2020-04-04T08:18:13.039988+00:00 app[web.1]: raise HaltServer(reason, self.WORKER_BOOT_ERROR)
2020-04-04T08:18:13.040026+00:00 app[web.1]: gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3>
2020-04-04T08:18:13.040027+00:00 app[web.1]: 
2020-04-04T08:18:13.040027+00:00 app[web.1]: During handling of the above exception, another exception occurred:
2020-04-04T08:18:13.040027+00:00 app[web.1]: 
2020-04-04T08:18:13.040028+00:00 app[web.1]: Traceback (most recent call last):
2020-04-04T08:18:13.040043+00:00 app[web.1]: File "/app/.heroku/python/bin/gunicorn", line 8, in <module>
2020-04-04T08:18:13.040152+00:00 app[web.1]: sys.exit(run())
2020-04-04T08:18:13.040154+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 58, in run
2020-04-04T08:18:13.040274+00:00 app[web.1]: WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
2020-04-04T08:18:13.040276+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 228, in run
2020-04-04T08:18:13.040433+00:00 app[web.1]: super().run()
2020-04-04T08:18:13.040435+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 72, in run
2020-04-04T08:18:13.040552+00:00 app[web.1]: Arbiter(self).run()
2020-04-04T08:18:13.040567+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 229, in run
2020-04-04T08:18:13.040777+00:00 app[web.1]: self.halt(reason=inst.reason, exit_status=inst.exit_status)
2020-04-04T08:18:13.040801+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 342, in halt
2020-04-04T08:18:13.041161+00:00 app[web.1]: self.stop()
2020-04-04T08:18:13.041180+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 393, in stop
2020-04-04T08:18:13.041558+00:00 app[web.1]: time.sleep(0.1)
2020-04-04T08:18:13.041578+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 242, in handle_chld
2020-04-04T08:18:13.041859+00:00 app[web.1]: self.reap_workers()
2020-04-04T08:18:13.041880+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 525, in reap_workers
2020-04-04T08:18:13.042432+00:00 app[web.1]: raise HaltServer(reason, self.WORKER_BOOT_ERROR)
2020-04-04T08:18:13.042469+00:00 app[web.1]: gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3>
2020-04-04T08:18:13.123367+00:00 heroku[web.1]: State changed from up to crashed
2020-04-04T08:18:27.000000+00:00 app[api]: Build succeeded
2020-04-04T08:20:32.245127+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=covid19-risk.herokuapp.com request_id=a884e87f-799a-43ef-8ef3-17eb50f3a899 fwd="69.209.23.53" dyno= connect= service= status=503 bytes= protocol=https
2020-04-04T08:20:32.831232+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=covid19-risk.herokuapp.com request_id=bf0f70e0-890a-4809-b861-77efcf2d0d7c fwd="69.209.23.53" dyno= connect= service= status=503 bytes= protocol=https

I suspect this issue has something to do Heroku and my local machine using different versions of XGBoost so the pickle file didn't run properly.我怀疑这个问题与 Heroku 和我的本地机器使用不同版本的 XGBoost 有关,因此泡菜文件无法正常运行。 If that's the case, what other ways can I use a trained model in Flask?如果是这种情况,我可以在 Flask 中使用经过训练的 model 的其他方式吗? Thanks!谢谢!

can't post a comment, hence writing it here不能发表评论,所以写在这里

Dependencies依赖项

change requirements.txt to pin down the exact versions of the packages, each lines in requirements should look like this更改requirements.txt以确定软件包的确切版本,需求中的每一行应该如下所示

flask==1.1.1

to do this, from you virtual environment shell check the output of pip freeze if the output looks correct, then run pip freeze > requirements.txt to update the requirements.txt file, also have look at Pipfile new way of managing dependencies in Python to do this, from you virtual environment shell check the output of pip freeze if the output looks correct, then run pip freeze > requirements.txt to update the requirements.txt file, also have look at Pipfile new way of managing dependencies in Python

Runtime运行

Add a runtime.txt file with at the root of the project to pin down the Python version you want on heroku, check docs here for available versions在项目的根目录中添加一个runtime.txt文件,以在 heroku 上确定您想要的 Python 版本,在此处查看文档以获取可用版本

python-3.7.2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM