2020-09-15: Work note for running an API server for machine learning, natural language processing, etc. on heroku.
First, create a minimal server and run it locally.
$ python3 -m venv venv$ source venv/bin/activatefrom flask import Flask
app = Flask(__name__)
def create_app():
return app
@app.route('/')
def root():
return "OK"
- Minimal server implementation
- I had a habit of doing app.run with `if __name__ == "__main__"`, but I don't do that anymore, even in official Flask tutorials.
- Specify the module to be started in the environment variable, and start it with flask run.
- [explanation on the heroku side](https://devcenter.heroku.com/articles/flask-memcache) does that too.
- Setting environment variables may seem tedious, but you can use dotenv
- The official explanation uses [Flask Blueprint](/en/Flask%20Blueprint), but I decided that's not necessary at the minimum.
- create_app is used to call from gunicorn later
$ python server/__init__.pyModuleNotFoundError: No module named 'flask'$ pip install --upgrade pip$ pip install flask$ flask runError: Could not locate a Flask application. You did not provide the "FLASK_APP" environment variable, and a "wsgi.py" or "app.py" module was not found in the current directory.
$ code .env
:FLASK_APP=server
FLASK_ENV=development
$ pip install python-dotenv$ flask runDeploy to heroku
$ git initvenv/
.env
*.pyc
__pycache__/
- .env ignore?
- If you don't IGNORE, you don't need to do $ heroku config:set FLASK_APP=server later
- This is to avoid the common accident of putting API keys, etc. that should not be made public in .env and pushing them to the public repository.
$ git add .
$ git commit -m 'minimal Flask server'
$ heroku create foo-server
$ heroku git:remote -a foo-server$ git remote
heroku
I'm going to push here.
$ git push --set-upstream heroku master$ pip install gunicorn
$ pip freeze > requirements.txt
create "Procfile" :
web: gunicorn server:"create_app()"
- name "server" points the module on "./server"
$ heroku config:set FLASK_APP=server$ git push heroku master$ heroku openImplement the required API
$ heroku logs --tailBy default, a route only answers to GET requests.doc@app.route('/', methods=['GET', 'POST'])property json: Optional[Any] doc: Incoming Request DataThe parsed JSON data if mimetype indicates JSON (application/json, see is_json).
"No web processes running"
This page is auto-translated from /nishio/Heroku+Flask using DeepL. If you looks something interesting but the auto-translated English is not good enough to understand it, feel free to let me know at @nishio_en. I'm very happy to spread my thought to non-Japanese readers.