Deploying a Flask app on a Heroku free dyno - Phelipe Teles

Deploying a Flask app on a Heroku free dyno

2 min.
View source code

diff
diff --git a/Procfile b/Procfileindex d49e1a0..0cd38da 100644--- a/Procfile+++ b/Procfile@@ -1 +1 @@-web: gunicorn "app:create_app()"+web: waitress-serve --port=$PORT --threads=${WEB_CONCURRENCY:-2} --call 'app:create_app'

Recently, I had trouble deploying a Flask application using gunicorn as the WSGI server on a Heroku’s free dyno tier.

The problem boils down to the application not restarting when the dyno is unidling, so once it sleeps it never wakes up again, unless you force it to do so with heroku restart.

From the heroku logs:

[No name]
2020-08-27T19:21:21.060020+00:00 heroku[web.1]: State changed from down to starting2020-08-27T19:21:26.527757+00:00 heroku[web.1]: Starting process with command `gunicorn "app:create_app()"`2020-08-27T19:21:34.069516+00:00 app[web.1]: [2020-08-27 19:21:34 +0000] [4] [INFO] Starting gunicorn 20.0.42020-08-27T19:21:34.087317+00:00 app[web.1]: [2020-08-27 19:21:34 +0000] [4] [INFO] Listening at: http://0.0.0.0:3906 (4)2020-08-27T19:21:34.092921+00:00 app[web.1]: [2020-08-27 19:21:34 +0000] [4] [INFO] Using worker: sync2020-08-27T19:21:34.131957+00:00 app[web.1]: [2020-08-27 19:21:34 +0000] [10] [INFO] Booting worker with pid: 102020-08-27T19:21:34.201582+00:00 app[web.1]: [2020-08-27 19:21:34 +0000] [11] [INFO] Booting worker with pid: 112020-08-27T19:21:34.560508+00:00 heroku[web.1]: State changed from starting to up2020-08-27T19:54:54.137845+00:00 heroku[web.1]: Idling2020-08-27T19:54:54.139855+00:00 heroku[web.1]: State changed from up to down2020-08-27T19:54:59.841651+00:00 heroku[web.1]: Stopping all processes with SIGTERM2020-08-27T19:54:59.908237+00:00 app[web.1]: [2020-08-27 19:54:59 +0000] [11] [INFO] Worker exiting (pid: 11)2020-08-27T19:54:59.910662+00:00 app[web.1]: [2020-08-27 19:54:59 +0000] [4] [INFO] Handling signal: term2020-08-27T19:54:59.919059+00:00 app[web.1]: [2020-08-27 19:54:59 +0000] [10] [INFO] Worker exiting (pid: 10)2020-08-27T19:55:00.122579+00:00 app[web.1]: [2020-08-27 19:55:00 +0000] [4] [INFO] Shutting down: Master2020-08-27T19:55:00.223868+00:00 heroku[web.1]: Process exited with status 0

Every request would then be met with a Heroku H10 error and 503 HTTP error.

I simply had this in my Procfile:

[No name]
web: gunicorn "app:create_app()"

I don’t know if there’s anything wrong with it or if I could have done something to make it restart when unidling. Please let me know if that’s the case.

By comparing with a node application log, the difference seems to be on how the processes handle a SIGTERM signal. node exits with code 143 and restarts just fine afterwards, but gunicorn exits with code 0 and doesn’t restart again.

I searched for a way to configure how gunicorn handles SIGTERM with no luck, but that would be too awkward anyway.

Then I stumbled upon a post discouraging the use of gunicorn on Heroku and recommending Waitress instead.

The mentioned blog post author’s reasons are much more technical than mine, I just wanted the application to not crash. So I changed the Procfile to:

[No name]
web: waitress-serve --port=$PORT --threads=${WEB_CONCURRENCY:-2} --call 'app:create_app'

As was suggested by the Flask and Waitress documentation

Now the application restarts when unidling:

[No name]
2020-10-09T02:02:24.121855+00:00 heroku[web.1]: Idling2020-10-09T02:02:24.123702+00:00 heroku[web.1]: State changed from up to down2020-10-09T02:02:25.226026+00:00 heroku[web.1]: Stopping all processes with SIGTERM2020-10-09T02:02:25.317332+00:00 heroku[web.1]: Process exited with status 1432020-10-09T13:22:44.966887+00:00 heroku[web.1]: Unidling2020-10-09T13:22:44.969344+00:00 heroku[web.1]: State changed from down to starting2020-10-09T13:22:49.127433+00:00 heroku[web.1]: Starting process with command `waitress-serve --port=55574 --threads=${WEB_CONCURRENCY:-2} --call 'app:create_app'`