diff --git a/.drone.yml b/.drone.yml index d2287d7..f6ec0df 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,10 +1,6 @@ --- matrix: include: - - IMAGE: 3.6-stretch - TOXENV: py36 - - IMAGE: 3.7-stretch - TOXENV: py37 - IMAGE: 3.8-buster TOXENV: py38 - IMAGE: 3.8-buster @@ -15,14 +11,10 @@ matrix: TOXENV: format - IMAGE: 3.8-buster TOXENV: type - - IMAGE: 3.8-buster - TOXENV: docs - - IMAGE: 3.8-buster - TOXENV: metadata-release pipeline: build: image: python:${IMAGE} commands: - - pip install tox==3.14.6 + - pip install tox - tox -e ${TOXENV} diff --git a/.envrc.sample b/.envrc.sample index 7dca380..991560b 100644 --- a/.envrc.sample +++ b/.envrc.sample @@ -1,6 +1,7 @@ -export CELERY_BROKER_URL=redis://localhost:6379/1 -export CELERY_RESULT_BACKEND=redis://localhost:6379/1 -export ENV=development +export CELERY_BROKER_URL=redis://localhost:6379 +export CELERY_RESULT_BACKEND=redis://localhost:6379 +export FLASK_ENV=development +export FLASK_APP=wsgi:app export REDIS_HOST=localhost export REDIS_PORT=6379 export REDIS_SESSION_DB=0 diff --git a/Dockerfile b/Dockerfile index e2554d8..6389ddf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,20 +7,23 @@ WORKDIR ${APP_ROOT} COPY . ${APP_ROOT} RUN apk add --update \ - build-base \ - curl \ - git \ - libffi-dev \ - libsasl \ + build-base \ + curl \ + git \ + libffi-dev \ + libsasl \ + openssl-dev \ python3-dev - RUN addgroup -S ${CELERY_USER} -RUN adduser -D \ - -h ${APP_ROOT} \ +RUN adduser -D \ + -h ${APP_ROOT} \ -s /usr/sbin/nologin \ - -G ${CELERY_USER} ${CELERY_USER} + -G ${CELERY_USER} \ + ${CELERY_USER} RUN pip install "poetry>=1.0.9,<2.0" -RUN poetry install +RUN poetry install \ + --no-dev \ + --no-interaction diff --git a/README.md b/README.md index 22cec34..30347fb 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,8 @@ A swarm of dreams. # Development -TODO. +``` +$ docker-compose up +``` + +Then see http://localhost:5000. diff --git a/celerybeat-schedule b/celerybeat-schedule new file mode 100644 index 0000000..bebe88a Binary files /dev/null and b/celerybeat-schedule differ diff --git a/celworker.py b/celworker.py index 8fb9129..e346e31 100644 --- a/celworker.py +++ b/celworker.py @@ -4,6 +4,6 @@ from os import environ from magic_app.app import celery, create_app # noqa from magic_app.config import CONFIG -config = CONFIG[environ["ENV"]] +config = CONFIG[environ["FLASK_ENV"]] app = create_app(config=config) app.app_context().push() diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..667c115 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,36 @@ +--- +version: "3.8" + +x-env: &env + environment: + CELERY_BROKER_URL: "redis://redis:6379" + CELERY_RESULT_BACKEND: "redis://redis:6379" + FLASK_APP: "wsgi:app" + FLASK_ENV: "development" + REDIS_HOST: "redis" + REDIS_PORT: "6379" + REDIS_SESSION_DB: "0" + +services: + flask: + build: . + <<: *env + ports: + - "5000:5000" + command: | + poetry run + flask run --host 0.0.0.0 + volumes: + - "./:/magic_app/" + + celery: + build: . + <<: *env + command: | + poetry run + celery worker -A celworker.celery -B -l debug + volumes: + - "./:/magic_app/" + + redis: + image: redis:alpine diff --git a/magic_app/app.py b/magic_app/app.py index f0c109e..dda2f14 100644 --- a/magic_app/app.py +++ b/magic_app/app.py @@ -7,7 +7,9 @@ from redis import Redis from magic_app.config import Base, Production -celery = Celery(__name__, broker=Base.CELERY_BROKER_URL) +celery = Celery( + __name__, backend=Base.CELERY_RESULT_BACKEND, broker=Base.CELERY_BROKER_URL +) def create_app(config=Production): @@ -15,8 +17,7 @@ def create_app(config=Production): app = Flask(__name__.split(".")[0]) app.config.from_object(config) - celery.conf.update(app.config) - + configure_celery(app) configure_redis(app) configure_views(app) configure_logging(app) @@ -28,11 +29,11 @@ def configure_redis(app): """Configure Redis connection.""" from magic_app.session import RedisSessionDB - host = (Base.REDIS_HOST,) - port = (Base.REDIS_PORT,) + host = Base.REDIS_HOST + port = Base.REDIS_PORT db_num = Base.REDIS_SESSION_DB - if app.debug: + if app.testing: from fakeredis import FakeRedis connection = FakeRedis() @@ -42,6 +43,18 @@ def configure_redis(app): app.config["SESSION"] = RedisSessionDB(connection) +def configure_celery(app): + """Configure celery.""" + celery.conf.update(app.config) + + class ContextTask(celery.Task): + def __call__(self, *args, **kwargs): + with app.app_context(): + return self.run(*args, **kwargs) + + celery.Task = ContextTask + + def configure_views(app): """Configure API resource views.""" from magic_app.views import home diff --git a/magic_app/config.py b/magic_app/config.py index 99939ac..bf04d1f 100644 --- a/magic_app/config.py +++ b/magic_app/config.py @@ -25,14 +25,16 @@ class Development(Base): """The Development configuration.""" ENV = "development" - DEBUG = True + CELERY_ALWAYS_EAGER = True + DEBUG = True class Testing(Base): """The testing configuration.""" ENV = "testing" + TESTING = True class Production(Base): diff --git a/magic_app/views.py b/magic_app/views.py index dcfcc94..355faca 100644 --- a/magic_app/views.py +++ b/magic_app/views.py @@ -6,4 +6,5 @@ home = Blueprint("home", __name__) @home.route("/") def hello_world(): + return "Hello, World" diff --git a/pyproject.toml b/pyproject.toml index 9529fa6..83bf660 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,8 @@ keywords = ["docker", "swarm", "packaging"] celery = "^4.4.6" flask = "^1.1.2" flask-wtf = "^0.14.3" -python = "^3.6" +gunicorn = "^20.0.4" +python = "^3.8" redis = "^3.5.3" [tool.poetry.dev-dependencies] diff --git a/tox.ini b/tox.ini index 58df933..2a6f9e9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - {py36,py37,py38} + py38 lint sort format @@ -9,12 +9,6 @@ skip_missing_interpreters = True isolated_build = True [testenv] -description = run the unit tests -deps = - pytest - pytest-cov - pytest-mock -commands = pytest test/ --cov={toxinidir}/magic_app/ --no-cov-on-fail {posargs} [testenv:lint] description = lint the source @@ -26,25 +20,23 @@ commands = flake8 {posargs} magic_app/ test/ description = sort the source skipdist = True deps = isort -commands = isort {posargs:-rc -c} -sp setup.cfg magic_app/ test/ +commands = isort {posargs:-c} -sp setup.cfg magic_app/ test/ [testenv:format] description = format the source skipdist = True -basepython = python3.8 deps = black commands = black {posargs:--check} magic_app/ test/ [testenv:type] description = type check the source -basepython = python3.8 skipdist = True deps = mypy commands = mypy magic_app/ test/ [testenv:release] description = make a release -deps = {[testenv:metadata-release]deps} +deps = twine commands = rm -rf {toxworkdir}/dist python -m setup sdist --dist-dir {toxworkdir}/dist bdist_wheel diff --git a/wsgi.py b/wsgi.py index 2bc1c81..7c2e3cb 100644 --- a/wsgi.py +++ b/wsgi.py @@ -4,5 +4,5 @@ import os from magic_app.app import create_app from magic_app.config import CONFIG -config = CONFIG[os.environ["ENV"]] +config = CONFIG[os.environ["FLASK_ENV"]] app = create_app(config=config)