Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ CMD ["poetry", "run", "python", "-m", "src"]

FROM base AS release
ARG RUN_USER
WORKDIR /app

# Gunicorn requires this workaround to create writable temporary directory in
# our readonly root file system. https://github.com/aws/containers-roadmap/issues/736
RUN mkdir -p /tmp
VOLUME ["/tmp"]

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

Expand Down Expand Up @@ -105,4 +109,4 @@ ENV HOST=0.0.0.0
USER ${RUN_USER}

# Run the application.
CMD ["poetry", "run", "python", "-m", "src"]
CMD ["poetry", "run", "gunicorn", "src.app:create_app()"]
25 changes: 25 additions & 0 deletions app/gunicorn.conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
Configuration file for the Gunicorn server used to run the application in production environments.

Attributes:
bind(str): The socket to bind. Formatted as '0.0.0.0:$PORT'.
workers(int): The number of worker processes for handling requests.
threads(int): The number of threads per worker for handling requests.

For more information, see https://docs.gunicorn.org/en/stable/configure.html
"""

import os

from src.app_config import AppConfig

app_config = AppConfig()

bind = app_config.host + ':' + str(app_config.port)
# Calculates the number of usable cores and doubles it. Recommended number of workers per core is two.
# https://docs.gunicorn.org/en/latest/design.html#how-many-workers
# We use 'os.sched_getaffinity(pid)' not 'os.cpu_count()' because it returns only allowable CPUs.
# os.sched_getaffinity(pid): Return the set of CPUs the process with PID pid is restricted to.
# os.cpu_count(): Return the number of CPUs in the system.
workers = len(os.sched_getaffinity(0)) * 2
threads = 4
22 changes: 21 additions & 1 deletion app/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pytz = "^2022.2.1"
APIFlask = "^1.1.3"
marshmallow-dataclass = {extras = ["enum", "union"], version = "^8.5.8"}
marshmallow = "^3.18.0"
gunicorn = "^21.2.0"

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

[tool.poetry.scripts]
app-start = "src.__main__:main"
db-migrate = "src.db.migrations.run:up"
db-migrate-down = "src.db.migrations.run:down"
db-migrate-down-all = "src.db.migrations.run:downall"
Expand Down
42 changes: 0 additions & 42 deletions app/src/__main__.py

This file was deleted.

2 changes: 0 additions & 2 deletions app/src/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@


class AppConfig(PydanticBaseEnvConfig):
environment: str = "prod"

# Set HOST to 127.0.0.1 by default to avoid other machines on the network
# from accessing the application. This is especially important if you are
# running the application locally on a public network. This needs to be
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ services:
args:
- RUN_UID=${RUN_UID:-4000}
- RUN_USER=${RUN_USER:-app}
command: ["poetry", "run", "flask", "--app", "src.app", "run", "--host", "0.0.0.0", "--port", "8080", "--reload"]
container_name: main-app
env_file: ./app/local.env
ports:
Expand Down
2 changes: 1 addition & 1 deletion docs/app/database/database-access-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This document describes the best practices and patterns for how the application

## Client Initialization and Configuration

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.
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.

## Session Management

Expand Down