Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. After getting the app successfully running on my local machine, I couldn't deploy it on Heroku without incurring "Application Error". (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:

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:

web: gunicorn app:app

Code in requirements.txt

flask
pandas
gunicorn
xgboost
sklearn

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. If that's the case, what other ways can I use a trained model in Flask? Thanks!

like image 497
ramund Avatar asked Nov 06 '22 08:11

ramund


1 Answers

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

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

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

python-3.7.2
like image 132
Zeeshan Khan Avatar answered Nov 14 '22 23:11

Zeeshan Khan