diff --git a/.python-version b/.python-version index 9575d51..0f44168 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.6.1 +3.6.4 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e157568..0000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: python - -python: - - "3.6" - - "3.5" - - "3.4" - - "2.7" - -install: - - pip install -r requirements.txt - -script: - - python manage.py test diff --git a/Dockerfile b/Dockerfile index 5628c26..24ec179 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM python:3.6.1 +# base image +FROM python:3.6.4-alpine # set working directory RUN mkdir -p /usr/src/app @@ -8,4 +9,4 @@ WORKDIR /usr/src/app ADD ./requirements.txt /usr/src/app/requirements.txt # install requirements -RUN pip install -r requirements.txt \ No newline at end of file +RUN pip install -r requirements.txt diff --git a/LICENSE b/LICENSE index e1757be..54a7a05 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ The MIT License (MIT) -Copyright (c) 2017 Michael Herman +Copyright (c) 2018 Michael Herman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index e600978..2d59f53 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,3 @@ $ docker-compose up -d ``` Open your browser to http://localhost:5001 - -### Example - -![](app.png) \ No newline at end of file diff --git a/app.png b/app.png deleted file mode 100644 index b5c233c..0000000 Binary files a/app.png and /dev/null differ diff --git a/docker-compose.yml b/docker-compose.yml index 439519f..a89077b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2.1' +version: '3.5' services: @@ -6,26 +6,34 @@ services: build: . image: web container_name: web - environment: - - APP_SETTINGS=project.server.config.DevelopmentConfig ports: - '5001:5000' - command: python manage.py runserver -h 0.0.0.0 + command: python manage.py run -h 0.0.0.0 volumes: - .:/usr/src/app + environment: + - FLASK_DEBUG=1 + - APP_SETTINGS=project.server.config.DevelopmentConfig depends_on: - redis worker: image: web - container_name: worker - environment: - - APP_SETTINGS=project.server.config.DevelopmentConfig command: python manage.py run_worker volumes: - .:/usr/src/app + environment: + - APP_SETTINGS=project.server.config.DevelopmentConfig depends_on: - redis redis: image: redis:3.2.11 + + dashboard: + build: ./project/dashboard + image: dashboard + container_name: dashboard + ports: + - '9181:9181' + command: rq-dashboard -H redis diff --git a/manage.py b/manage.py index 0efa129..1af94fd 100644 --- a/manage.py +++ b/manage.py @@ -1,20 +1,20 @@ # manage.py -import os import unittest import redis from rq import Connection, Worker -from flask_script import Manager +from flask.cli import FlaskGroup -from project.server import app +from project.server import create_app -manager = Manager(app) +app = create_app() +cli = FlaskGroup(create_app=create_app) -@manager.command +@cli.command() def test(): """Runs the unit tests without test coverage.""" tests = unittest.TestLoader().discover('project/tests', pattern='test*.py') @@ -24,7 +24,7 @@ def test(): return 1 -@manager.command +@cli.command() def run_worker(): redis_url = app.config['REDIS_URL'] redis_connection = redis.from_url(redis_url) @@ -32,5 +32,6 @@ def run_worker(): worker = Worker(app.config['QUEUES']) worker.work() + if __name__ == '__main__': - manager.run() + cli() diff --git a/project/client/static/main.js b/project/client/static/main.js index c5a1265..61c8bdc 100644 --- a/project/client/static/main.js +++ b/project/client/static/main.js @@ -15,8 +15,8 @@ $('.btn').on('click', function() { }) .fail((err) => { console.log(err) - }) -}) + }); +}); function getStatus(taskID) { $.ajax({ @@ -30,7 +30,7 @@ function getStatus(taskID) { ${res.data.task_status} ${res.data.task_result} ` - $('#tasks').prepend(html) + $('#tasks').prepend(html); const taskStatus = res.data.task_status; if (taskStatus === 'finished' || taskStatus === 'failed') return false; setTimeout(function() { @@ -39,6 +39,5 @@ function getStatus(taskID) { }) .fail((err) => { console.log(err) - }) + }); } - diff --git a/project/client/templates/_base.html b/project/client/templates/_base.html index 8cb66d0..31ad653 100644 --- a/project/client/templates/_base.html +++ b/project/client/templates/_base.html @@ -9,7 +9,7 @@ - + {% block css %}{% endblock %} @@ -25,8 +25,8 @@ - - + + {% block js %}{% endblock %} diff --git a/project/dashboard/Dockerfile b/project/dashboard/Dockerfile new file mode 100644 index 0000000..292552a --- /dev/null +++ b/project/dashboard/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.6.4-alpine + +RUN pip install rq-dashboard + +EXPOSE 9181 + +CMD ["rq-dashboard"] diff --git a/project/server/__init__.py b/project/server/__init__.py index eb05a49..c768578 100644 --- a/project/server/__init__.py +++ b/project/server/__init__.py @@ -7,18 +7,31 @@ from flask_bootstrap import Bootstrap -app = Flask( - __name__, - template_folder='../client/templates', - static_folder='../client/static' -) +# instantiate the extensions +bootstrap = Bootstrap() -app_settings = os.getenv('APP_SETTINGS', 'project.server.config.DevelopmentConfig') -app.config.from_object(app_settings) +def create_app(script_info=None): -bootstrap = Bootstrap(app) + # instantiate the app + app = Flask( + __name__, + template_folder='../client/templates', + static_folder='../client/static' + ) + # set config + app_settings = os.getenv('APP_SETTINGS') + app.config.from_object(app_settings) -from project.server.main.views import main_blueprint -app.register_blueprint(main_blueprint) + # set up extensions + bootstrap.init_app(app) + + # register blueprints + from project.server.main.views import main_blueprint + app.register_blueprint(main_blueprint) + + # shell context for flask cli + app.shell_context_processor({'app': app}) + + return app diff --git a/project/server/config.py b/project/server/config.py index 055adff..94fe3c4 100644 --- a/project/server/config.py +++ b/project/server/config.py @@ -6,25 +6,18 @@ class BaseConfig(object): """Base configuration.""" - DEBUG = False WTF_CSRF_ENABLED = True REDIS_URL = 'redis://redis:6379/0' QUEUES = ['default'] + class DevelopmentConfig(BaseConfig): """Development configuration.""" - DEBUG = True WTF_CSRF_ENABLED = False class TestingConfig(BaseConfig): """Testing configuration.""" - DEBUG = True TESTING = True WTF_CSRF_ENABLED = False PRESERVE_CONTEXT_ON_EXCEPTION = False - - -class ProductionConfig(BaseConfig): - """Production configuration.""" - DEBUG = False diff --git a/project/server/main/tasks.py b/project/server/main/tasks.py index 80faf77..d4a3964 100644 --- a/project/server/main/tasks.py +++ b/project/server/main/tasks.py @@ -6,4 +6,4 @@ def create_task(task_type): time.sleep(int(task_type) * 10) - return True \ No newline at end of file + return True diff --git a/project/server/main/views.py b/project/server/main/views.py index 3524447..0a2c1f3 100644 --- a/project/server/main/views.py +++ b/project/server/main/views.py @@ -2,11 +2,13 @@ import redis -from rq import Queue, push_connection, pop_connection -from flask import current_app, render_template, Blueprint, jsonify, request +from rq import Queue, Connection +from flask import render_template, Blueprint, jsonify, \ + request, current_app from project.server.main.tasks import create_task + main_blueprint = Blueprint('main', __name__,) @@ -18,8 +20,9 @@ def home(): @main_blueprint.route('/tasks', methods=['POST']) def run_task(): task_type = request.form['type'] - q = Queue() - task = q.enqueue(create_task, task_type) + with Connection(redis.from_url(current_app.config['REDIS_URL'])): + q = Queue() + task = q.enqueue(create_task, task_type) response_object = { 'status': 'success', 'data': { @@ -31,8 +34,9 @@ def run_task(): @main_blueprint.route('/tasks/', methods=['GET']) def get_status(task_id): - q = Queue() - task = q.fetch_job(task_id) + with Connection(redis.from_url(current_app.config['REDIS_URL'])): + q = Queue() + task = q.fetch_job(task_id) if task: response_object = { 'status': 'success', @@ -41,17 +45,7 @@ def get_status(task_id): 'task_status': task.get_status(), 'task_result': task.result, } - } + } else: response_object = {'status': 'error'} return jsonify(response_object) - - -@main_blueprint.before_request -def push_rq_connection(): - push_connection(redis.from_url(current_app.config['REDIS_URL'])) - - -@main_blueprint.teardown_request -def pop_rq_connection(exception=None): - pop_connection() \ No newline at end of file diff --git a/project/tests/base.py b/project/tests/base.py index 8078acc..6ad9fc1 100644 --- a/project/tests/base.py +++ b/project/tests/base.py @@ -3,7 +3,9 @@ from flask_testing import TestCase -from project.server import app +from project.server import create_app + +app = create_app() class BaseTestCase(TestCase): diff --git a/project/tests/test__config.py b/project/tests/test__config.py index dcd9284..85defa0 100644 --- a/project/tests/test__config.py +++ b/project/tests/test__config.py @@ -1,4 +1,4 @@ -# project/server/tests/test_config.py +# project/server/tests/test__config.py import unittest @@ -6,7 +6,9 @@ from flask import current_app from flask_testing import TestCase -from project.server import app +from project.server import create_app + +app = create_app() class TestDevelopmentConfig(TestCase): @@ -34,17 +36,5 @@ def test_app_is_testing(self): self.assertTrue(app.config['WTF_CSRF_ENABLED'] is False) -class TestProductionConfig(TestCase): - - def create_app(self): - app.config.from_object('project.server.config.ProductionConfig') - return app - - def test_app_is_production(self): - self.assertFalse(current_app.config['TESTING']) - self.assertTrue(app.config['DEBUG'] is False) - self.assertTrue(app.config['WTF_CSRF_ENABLED'] is True) - - if __name__ == '__main__': unittest.main() diff --git a/requirements.txt b/requirements.txt index 71b6ac6..e0825f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,4 @@ Flask-Script==2.0.6 Flask-Testing==0.6.2 Flask-WTF==0.14.2 redis==2.10.6 -rq==0.8.2 \ No newline at end of file +rq==0.10.0