Skip to content

Commit 5297c13

Browse files
authored
Run flask using production wsgi/http server (#185)
1 parent 75df51b commit 5297c13

File tree

8 files changed

+55
-49
lines changed

8 files changed

+55
-49
lines changed

app/Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ CMD ["poetry", "run", "python", "-m", "src"]
6565

6666
FROM base AS release
6767
ARG RUN_USER
68-
WORKDIR /app
68+
69+
# Gunicorn requires this workaround to create writable temporary directory in
70+
# our readonly root file system. https://github.com/aws/containers-roadmap/issues/736
71+
RUN mkdir -p /tmp
72+
VOLUME ["/tmp"]
6973

7074
# TODO(https://github.com/navapbc/template-application-flask/issues/23) Productionize the Docker image
7175

@@ -105,4 +109,4 @@ ENV HOST=0.0.0.0
105109
USER ${RUN_USER}
106110

107111
# Run the application.
108-
CMD ["poetry", "run", "python", "-m", "src"]
112+
CMD ["poetry", "run", "gunicorn", "src.app:create_app()"]

app/gunicorn.conf.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""
2+
Configuration file for the Gunicorn server used to run the application in production environments.
3+
4+
Attributes:
5+
bind(str): The socket to bind. Formatted as '0.0.0.0:$PORT'.
6+
workers(int): The number of worker processes for handling requests.
7+
threads(int): The number of threads per worker for handling requests.
8+
9+
For more information, see https://docs.gunicorn.org/en/stable/configure.html
10+
"""
11+
12+
import os
13+
14+
from src.app_config import AppConfig
15+
16+
app_config = AppConfig()
17+
18+
bind = app_config.host + ':' + str(app_config.port)
19+
# Calculates the number of usable cores and doubles it. Recommended number of workers per core is two.
20+
# https://docs.gunicorn.org/en/latest/design.html#how-many-workers
21+
# We use 'os.sched_getaffinity(pid)' not 'os.cpu_count()' because it returns only allowable CPUs.
22+
# os.sched_getaffinity(pid): Return the set of CPUs the process with PID pid is restricted to.
23+
# os.cpu_count(): Return the number of CPUs in the system.
24+
workers = len(os.sched_getaffinity(0)) * 2
25+
threads = 4

app/poetry.lock

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pytz = "^2022.2.1"
1919
APIFlask = "^1.1.3"
2020
marshmallow-dataclass = {extras = ["enum", "union"], version = "^8.5.8"}
2121
marshmallow = "^3.18.0"
22+
gunicorn = "^21.2.0"
2223

2324
[tool.poetry.group.dev.dependencies]
2425
black = "^22.6.0"
@@ -42,7 +43,6 @@ requires = ["poetry-core>=1.0.0"]
4243
build-backend = "poetry.core.masonry.api"
4344

4445
[tool.poetry.scripts]
45-
app-start = "src.__main__:main"
4646
db-migrate = "src.db.migrations.run:up"
4747
db-migrate-down = "src.db.migrations.run:down"
4848
db-migrate-down-all = "src.db.migrations.run:downall"

app/src/__main__.py

Lines changed: 0 additions & 42 deletions
This file was deleted.

app/src/app_config.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33

44
class AppConfig(PydanticBaseEnvConfig):
5-
environment: str = "prod"
6-
75
# Set HOST to 127.0.0.1 by default to avoid other machines on the network
86
# from accessing the application. This is especially important if you are
97
# running the application locally on a public network. This needs to be

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ services:
2020
args:
2121
- RUN_UID=${RUN_UID:-4000}
2222
- RUN_USER=${RUN_USER:-app}
23+
command: ["poetry", "run", "flask", "--app", "src.app", "run", "--host", "0.0.0.0", "--port", "8080", "--reload"]
2324
container_name: main-app
2425
env_file: ./app/local.env
2526
ports:

docs/app/database/database-access-management.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This document describes the best practices and patterns for how the application
44

55
## Client Initialization and Configuration
66

7-
The database client is initialized when the application starts (see [src/\_\_main\_\_.py](../../../app/src/__main__.py). As the database engine that is used to create acquire connections to the database is initialized using the database configuration defined in [db_config.py](../../../app/src/db/db_config.py), which is configured through environment variables. The initialized database client is then stored on the Flask app's [\`extensions\` dictionary](https://flask.palletsprojects.com/en/2.2.x/src/#flask.Flask.extensions) to be used throughout the lifetime of the application.
7+
The database client is initialized when the application starts (see [src/\_\_main\_\_.py](../../../app/src/app.py). The database engine that is used to create acquire connections to the database is initialized using the database configuration defined in [db_config.py](../../../app/src/db/db_config.py), which is configured through environment variables. The initialized database client is then stored on the Flask app's [\`extensions\` dictionary](https://flask.palletsprojects.com/en/2.2.x/src/#flask.Flask.extensions) to be used throughout the lifetime of the application.
88

99
## Session Management
1010

0 commit comments

Comments
 (0)