diff --git a/{{cookiecutter.project_name}}/docker-compose.prod.yml b/{{cookiecutter.project_name}}/docker-compose.prod.yml new file mode 100644 index 0000000000000000000000000000000000000000..39cefc8d0a73ec4ad41a358a65db04db969e4114 --- /dev/null +++ b/{{cookiecutter.project_name}}/docker-compose.prod.yml @@ -0,0 +1,68 @@ +# Local docker-compose configuration + +version: '3.7' + +services: + back: + container_name: {{ cookiecutter.project_name }}_backend + build: + context: . + target: production + labels: + {{ cookiecutter.project_name }}.description: {{ cookiecutter.project_description }} + env_file: + - envs/.env + ports: + - 8402:8000 + depends_on: + - db + networks: + - {{ cookiecutter.project_name }}_network + + db: + container_name: {{ cookiecutter.project_name }}_db + image: postgres:12.4 + volumes: + - {{ cookiecutter.project_name }}_db_data:/var/lib/postgresql/data + networks: + - {{ cookiecutter.project_name }}_network + env_file: + - envs/.env + + {% if cookiecutter.add_redis == "True" -%} + redis: + container_name: {{ cookiecutter.project_name }}_redis + image: bitnami/redis:6.0.7 + volumes: + - {{ cookiecutter.project_name }}_redis_data:/bitnami/redis/data + env_file: + - envs/.env + networks: + - {{ cookiecutter.project_name }}_network + {% endif %} + + {% if cookiecutter.add_scheduler == "True" -%} + scheduler: + container_name: {{ cookiecutter.project_name }}_scheduler + build: + context: . + target: scheduler + labels: + scheduler.description: "{{ cookiecutter.project_name }} scheduler image" + env_file: + - envs/.env + volumes: + - ./:/app + depends_on: + - db + networks: + - {{ cookiecutter.project_name }}_network + {% endif %} + +volumes: + {{ cookiecutter.project_name }}_db_data: + {{ cookiecutter.project_name }}_redis_data: + +networks: + {{ cookiecutter.project_name }}_network: + name: {{ cookiecutter.project_name }}_network \ No newline at end of file diff --git a/{{cookiecutter.project_name}}/docker-compose.yml b/{{cookiecutter.project_name}}/docker-compose.yml index 6f5a5e15b201368c502817f02e5ce7b50adf6115..c9821bf56c30a54a78f26f21c65f7e54a4f96d74 100644 --- a/{{cookiecutter.project_name}}/docker-compose.yml +++ b/{{cookiecutter.project_name}}/docker-compose.yml @@ -4,12 +4,12 @@ version: '3.7' services: back: - container_name: {{ cookiecutter.project_name }}_backend + container_name: {{ cookiecutter.project_name }}_backend_dev build: context: . target: development labels: - detector.description: {{ cookiecutter.project_description }} + {{ cookiecutter.project_name }}.description: {{ cookiecutter.project_description }} env_file: - envs/.env ports: @@ -19,35 +19,37 @@ services: depends_on: - db networks: - - {{ cookiecutter.project_name }}_network + - {{ cookiecutter.project_name }}_network_dev db: - container_name: {{ cookiecutter.project_name }}_db + container_name: {{ cookiecutter.project_name }}_db_dev image: postgres:12.4 volumes: - - {{ cookiecutter.project_name }}_db_data:/var/lib/postgresql/data + - {{ cookiecutter.project_name }}_db_data_dev:/var/lib/postgresql/data ports: - 5432:5432 networks: - - {{ cookiecutter.project_name }}_network + - {{ cookiecutter.project_name }}_network_dev env_file: - envs/.env + {% if cookiecutter.add_redis == "True" -%} redis: - container_name: {{ cookiecutter.project_name }}_redis + container_name: {{ cookiecutter.project_name }}_redis_dev image: bitnami/redis:6.0.7 volumes: - - {{ cookiecutter.project_name }}_redis_data:/bitnami/redis/data + - {{ cookiecutter.project_name }}_redis_data_dev:/bitnami/redis/data env_file: - envs/.env ports: - 6379:6379 networks: - - {{ cookiecutter.project_name }}_network + - {{ cookiecutter.project_name }}_network_dev + {% endif %} {% if cookiecutter.add_scheduler == "True" -%} scheduler: - container_name: {{ cookiecutter.project_name }}_scheduler + container_name: {{ cookiecutter.project_name }}_scheduler_dev build: context: . target: scheduler @@ -60,13 +62,13 @@ services: depends_on: - db networks: - - {{ cookiecutter.project_name }}_network + - {{ cookiecutter.project_name }}_network_dev {% endif %} volumes: - {{ cookiecutter.project_name }}_db_data: - {{ cookiecutter.project_name }}_redis_data: + {{ cookiecutter.project_name }}_db_data_dev: + {{ cookiecutter.project_name }}_redis_data_dev: networks: - {{ cookiecutter.project_name }}_network: - name: {{ cookiecutter.project_name }}_network \ No newline at end of file + {{ cookiecutter.project_name }}_network_dev: + name: {{ cookiecutter.project_name }}_network_dev \ No newline at end of file diff --git a/{{cookiecutter.project_name}}/main.py b/{{cookiecutter.project_name}}/main.py index 93ef9a0ed97f17e1949d7876b9fb9117a83bcecf..262ac78c298c40ae7c1dfe3f3f1db00fb0345cdd 100644 --- a/{{cookiecutter.project_name}}/main.py +++ b/{{cookiecutter.project_name}}/main.py @@ -1,8 +1,45 @@ -import uvicorn +import argparse +from typing import Any, Dict, Optional + +from fastapi import FastAPI +from gunicorn.app.base import BaseApplication + +from src.server import app + + +class StandaloneApplication(BaseApplication): + def __init__(self, application_instance: FastAPI, run_options: Optional[Dict[str, Any]] = None): + self.options = run_options or {} + self.application = application_instance + super().__init__() + + def load_config(self) -> None: + config = { + key: value + for key, value in self.options.items() + if key in self.cfg.settings and value is not None + } + for key, value in config.items(): + self.cfg.set(key.lower(), value) + + def load(self) -> FastAPI: + return self.application + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--host", type=str, default="0.0.0.0") + parser.add_argument("--port", type=int, default=8000) + parser.add_argument("--pid-file", type=str, default="/tmp/fastapi_service.pid") + return parser.parse_args() -from src.settings import settings if __name__ == "__main__": - uvicorn.run( - "src.server:app", host="0.0.0.0", port=8000, log_level=settings.log_level - ) + args = parse_args() + options = { + "bind": f"{args.host}:{args.port}", + "workers": 1, + "worker_class": "uvicorn.workers.UvicornWorker", + "pidfile": args.pid_file, + } + StandaloneApplication(app, options).run() diff --git a/{{cookiecutter.project_name}}/pyproject.toml b/{{cookiecutter.project_name}}/pyproject.toml index ed6319a320f1433c50ea9695a5d29f9eb8fe4ef5..cccff169f0fbd8b7c362e775b5b3efc14ca78383 100644 --- a/{{cookiecutter.project_name}}/pyproject.toml +++ b/{{cookiecutter.project_name}}/pyproject.toml @@ -12,6 +12,9 @@ sqlalchemy = "^1.3.19" loguru = "^0.5.2" alembic = "^1.4.3" httpx = "^0.14.3" +ujson = "^4.0.1" +gunicorn = "^20.0.4" +httptools = "^0.1.1" {% if cookiecutter.pg_driver == "aiopg" -%} aiopg = "^1.0.0" {% else %} diff --git a/{{cookiecutter.project_name}}/src/server.py b/{{cookiecutter.project_name}}/src/server.py index 03c59a42051811cb34a9810d9eac83aaf1c54faf..8eb633a7c3dadc68c9c0bf56e752730152997d88 100644 --- a/{{cookiecutter.project_name}}/src/server.py +++ b/{{cookiecutter.project_name}}/src/server.py @@ -5,6 +5,7 @@ import alembic.config from fastapi import FastAPI from loguru import logger from starlette.requests import Request +from starlette.responses import UJSONResponse from src.api import api_router {% if cookiecutter.pg_driver == "aiopg" -%} @@ -31,6 +32,7 @@ logger.configure( app = FastAPI( title="{{cookiecutter.project_name}}", description="{{cookiecutter.project_description}}", + default_response_class=UJSONResponse ) app.include_router(prefix="", router=api_router)