# Back-end Production Server

* **Status:** Accepted
* **Last Modified:** 2023-07-2i
* **Related Issue:** [#245](https://github.com/HHS/simpler-grants-gov/issues/245)
* **Deciders:** Daphne, Sammy, Billy, Lucas
* **Tags:** ADR

## Context and Problem Statement

The Flask development server is not meant for production use and only intended for local development. It is not secure, stable, efficient, or scaled for a production environment. In addition to choosing a production server, this ADR will specify a high level implementation option.

## Decision Drivers

* **Scalable:** The chosen solution should be configurable to scale and a multi-worker, multi-threaded production-ready, WSGI wrapper.
* **Ease of use:** The production server should be relatively simple to set up and start.
* **Well-maintained:** We have a preference towards a production server that is widely adopted and have active maintainers.

## Options Considered

### Production Server

* Gunicorn
* Waitress

### Implementation

1. API entrypoint responsible for conditional logic determining dev vs prod environment and starting corresponding server
2. Dockerfile executable command for the prod server is overridden in the IaC [task definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html), API by default starts dev server
3. Dockerfile executable command for the dev server is overridden in `docker-compose.yml`, API by default starts prod server

Note: Gunicorn can be set up either using their unique [configuration file](https://docs.gunicorn.org/en/latest/configure.html) or in our code using separate app entry points for dev and prod. We want to make sure we are scaling the appropriate number of workers based on CPU.

## Decision Outcome

### Production Server

Chosen option: Gunicorn, because it is the industry standard, well-supported and documented.

### Implementation

Chosen option: #3 Dockerfile executable command for the dev server is overridden in `docker-compose.yml`, API by default starts prod server. This is because it makes the most sense in our current development ecosystem and abstracts away the concept of environment in the API layer.

## Pros and Cons of the Options

### Production Server

#### [Gunicorn](https://gunicorn.org/)

* **Pros**
  * Widely used, industry standard Python server
  * Excellent ability to manage workers
  * Simple and light on resources, written in C
  * Highly compatible with most Python tooling
* **Cons**
  * Does not run on Windows without WSL 🧐

#### [Waitress](https://github.com/Pylons/waitress)

* **Pros**
  * Simple, lightweight
  * Can run on Windows as well as UNIX systems
  * No dependencies that aren't part of the standard Python library
  * Purely Python
* **Cons**
  * Runs on CPython and has "very acceptable performance"

### Implementation

#### #1 API entrypoint responsible for conditional logic determining dev vs prod environment and starting corresponding server

* **Pros**
  * This is how the Flask app is already configured (small lift to modify)
* **Cons**
  * Poor separation of concerns: apps remaining environment agnostic keeps them much simpler overall
  * Can lead to confusing environment conditional logic

#### #2 Dockerfile executable command for the prod server is overridden in the IaC [task definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html), API by default starts dev server

* **Pros**
  * Terraform handles our infrastructure and deployments, therefore conceptually makes sense to define Docker run commands in the task definition
* **Cons**
  * Ignores `docker-compose.yml` for local development as a tool we have at our disposal
  * Obscures prod server run command outside app ecosystem in IaC
  * Implementation could potentially use separate app entry points for dev and prod

#### #3 Dockerfile executable command for the dev server is overridden in `docker-compose.yml`, API by default starts prod server

* **Pros**
  * Local development is done via `docker-compose.yml` config, so it makes a ton of conceptual sense to pass a local Docker run command here
* **Cons**
  * Implementation could potentially use separate app entry points for dev and prod


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.simpler.grants.gov/product/decisions/adr/2023-07-26-backend-prod-server.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
