diff --git a/README.md b/README.md index 1f3ff59..471ca04 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ Docker Hub: [pfeiffermax/uvicorn-gunicorn-poetry](https://hub.docker.com/r/pfeif GitHub Repository: [https://github.com/max-pfeiffer/uvicorn-gunicorn-poetry](https://github.com/max-pfeiffer/uvicorn-gunicorn-poetry) +**IMPORTANT:** Please be aware of a bug with Gunicorn: [worker reload with Uvicorn workers is currently broken.](https://github.com/benoitc/gunicorn/issues/2339) +So the latest version of that image does not provide that functionality any more. + ## Usage It just provides a platform that you can use to build upon your own multistage builds. So it consequently does not contain an application itself. Please check out the [example application](https://github.com/max-pfeiffer/uvicorn-gunicorn-poetry/tree/master/examples/fast_api_multistage_build) @@ -83,11 +86,6 @@ if you would like to do a deep dive. Following environment variables are support **default:** `-` -### [Debugging](https://docs.gunicorn.org/en/stable/settings.html#debugging) -`RELOAD` : Restart workers when code changes. - -**default:** `False` - ### [Worker processes](https://docs.gunicorn.org/en/stable/settings.html#worker-processes) `WORKERS` : The number of worker processes for handling requests. By default this is set to one worker as this image is meant to be used on a production grade Kubernetes environment. There you diff --git a/build/gunicorn_configuration.py b/build/gunicorn_configuration.py index ab28f6f..2c5ac37 100644 --- a/build/gunicorn_configuration.py +++ b/build/gunicorn_configuration.py @@ -10,7 +10,7 @@ "loglevel": "info", "accesslog": "-", "errorlog": "-", - "reload": False, +# "reload": False, "worker_tmp_dir": "/dev/shm", } @@ -22,7 +22,11 @@ # Debugging # https://docs.gunicorn.org/en/stable/settings.html#debugging -reload = bool(os.getenv("RELOAD", DEFAULT_GUNICORN_CONFIG["reload"])) + +# There is a bug with Gunicorn reload with uvicorn workers, so this features is +# not available any more until this bug became fixed +# see: https://github.com/benoitc/gunicorn/issues/2339 +# reload = bool(os.getenv("RELOAD", DEFAULT_GUNICORN_CONFIG["reload"])) # Worker processes # https://docs.gunicorn.org/en/stable/settings.html#worker-processes @@ -53,7 +57,7 @@ "loglevel": loglevel, "errorlog": errorlog, "accesslog": accesslog, - "reload": reload, +# "reload": reload, "worker_tmp_dir": worker_tmp_dir, } print(json.dumps(log_data)) diff --git a/examples/fast_api_multistage_build/Dockerfile b/examples/fast_api_multistage_build/Dockerfile index ae39976..600d39d 100644 --- a/examples/fast_api_multistage_build/Dockerfile +++ b/examples/fast_api_multistage_build/Dockerfile @@ -1,4 +1,4 @@ -ARG BASE_IMAGE_NAME_AND_TAG=pfeiffermax/uvicorn-gunicorn-poetry:python3.9.8-slim-bullseye-2021-11-15 +ARG BASE_IMAGE_NAME_AND_TAG=pfeiffermax/uvicorn-gunicorn-poetry:1.0.0-python3.9.8-slim-bullseye FROM ${BASE_IMAGE_NAME_AND_TAG} as base-image WORKDIR /application_root @@ -40,7 +40,7 @@ CMD ["--cov=app", "--cov-report=xml:/test_coverage_reports/unit_tests_coverage.x FROM base-image as development-image ENV WORKERS="1" \ - RELOAD="True" \ +# RELOAD="True" \ LOG_LEVEL="debug" COPY --from=base-image $VIRTUAL_ENVIRONMENT_PATH $VIRTUAL_ENVIRONMENT_PATH diff --git a/examples/fast_api_multistage_build/poetry.lock b/examples/fast_api_multistage_build/poetry.lock index 9d8e3c4..dcb1188 100644 --- a/examples/fast_api_multistage_build/poetry.lock +++ b/examples/fast_api_multistage_build/poetry.lock @@ -1,6 +1,6 @@ [[package]] name = "anyio" -version = "3.3.4" +version = "3.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" category = "main" optional = false @@ -12,7 +12,7 @@ sniffio = ">=1.1" [package.extras] doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] -test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] trio = ["trio (>=0.16)"] [[package]] @@ -187,14 +187,14 @@ python-versions = "*" [[package]] name = "packaging" -version = "21.2" +version = "21.3" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2,<3" +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "pathspec" @@ -253,11 +253,14 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pyparsing" -version = "2.4.7" +version = "3.0.6" description = "Python parsing module" category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.6" + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" @@ -361,11 +364,11 @@ python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "3.10.0.2" -description = "Backported and Experimental Type Hints for Python 3.5+" +version = "4.0.0" +description = "Backported and Experimental Type Hints for Python 3.6+" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "urllib3" @@ -398,13 +401,13 @@ standard = ["websockets (>=9.1)", "httptools (>=0.2.0,<0.3.0)", "watchgod (>=0.6 [metadata] lock-version = "1.1" -python-versions = "3.9.8" -content-hash = "eb9f92a2714459e3dfce1ddb816f8cfb433ce79a05baa48aa28fed4c8c627abf" +python-versions = "3.9.*" +content-hash = "02f080de4489491665f6605bcf7ceb243dfeb873e81e9952c357c7d5765d0b02" [metadata.files] anyio = [ - {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, - {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, + {file = "anyio-3.4.0-py3-none-any.whl", hash = "sha256:2855a9423524abcdd652d942f8932fda1735210f77a6b392eafd9ff34d3fe020"}, + {file = "anyio-3.4.0.tar.gz", hash = "sha256:24adc69309fb5779bc1e06158e143e0b6d2c56b302a3ac3de3083c705a6ed39d"}, ] asgiref = [ {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, @@ -511,8 +514,8 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ - {file = "packaging-21.2-py3-none-any.whl", hash = "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0"}, - {file = "packaging-21.2.tar.gz", hash = "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966"}, + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, @@ -555,8 +558,8 @@ pydantic = [ {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, ] pyparsing = [ - {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, - {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, + {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"}, + {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"}, ] pytest = [ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, @@ -638,9 +641,7 @@ tomli = [ {file = "tomli-1.2.2.tar.gz", hash = "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, + {file = "typing_extensions-4.0.0-py3-none-any.whl", hash = "sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9"}, ] urllib3 = [ {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, diff --git a/examples/fast_api_multistage_build/pyproject.toml b/examples/fast_api_multistage_build/pyproject.toml index 1275916..959f6b5 100644 --- a/examples/fast_api_multistage_build/pyproject.toml +++ b/examples/fast_api_multistage_build/pyproject.toml @@ -24,6 +24,11 @@ testpaths = [ "tests", ] +# https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file +[tool.black] +line-length = 80 +target-version = ['py39'] + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/pyproject.toml b/pyproject.toml index 1e8be69..07a41ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,10 +19,16 @@ black = "21.10b0" # https://docs.pytest.org/en/latest/reference/customize.html [tool.pytest.ini_options] +addopts = "--ignore=tests/functionality/test_worker_reload.py" testpaths = [ "tests", ] +# https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file +[tool.black] +line-length = 80 +target-version = ['py39'] + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/tests/configuration/test_default_configuration.py b/tests/configuration/test_default_configuration.py index 0e22b36..7c97b4c 100644 --- a/tests/configuration/test_default_configuration.py +++ b/tests/configuration/test_default_configuration.py @@ -29,7 +29,7 @@ def verify_container(container: UvicornGunicornPoetryContainerConfig) -> None: assert config_data["loglevel"] == DEFAULT_GUNICORN_CONFIG["loglevel"] assert config_data["accesslog"] == DEFAULT_GUNICORN_CONFIG["accesslog"] assert config_data["errorlog"] == DEFAULT_GUNICORN_CONFIG["errorlog"] - assert config_data["reload"] == DEFAULT_GUNICORN_CONFIG["reload"] +# assert config_data["reload"] == DEFAULT_GUNICORN_CONFIG["reload"] assert ( config_data["worker_tmp_dir"] == DEFAULT_GUNICORN_CONFIG["worker_tmp_dir"] diff --git a/tests/configuration/test_development_configuration.py b/tests/configuration/test_development_configuration.py index 2cf928a..1f9c52c 100644 --- a/tests/configuration/test_development_configuration.py +++ b/tests/configuration/test_development_configuration.py @@ -33,7 +33,7 @@ def verify_container(container: UvicornGunicornPoetryContainerConfig) -> None: assert config_data["loglevel"] == DEVELOPMENT_GUNICORN_CONFIG["loglevel"] assert config_data["accesslog"] == DEVELOPMENT_GUNICORN_CONFIG["accesslog"] assert config_data["errorlog"] == DEVELOPMENT_GUNICORN_CONFIG["errorlog"] - assert config_data["reload"] == DEVELOPMENT_GUNICORN_CONFIG["reload"] +# assert config_data["reload"] == DEVELOPMENT_GUNICORN_CONFIG["reload"] assert ( config_data["worker_tmp_dir"] == DEVELOPMENT_GUNICORN_CONFIG["worker_tmp_dir"]