diff --git a/app/main/views.py b/app/main/views.py index f26ba50..46e34d4 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -9,21 +9,39 @@ :license: BSD 2-Clause, see LICENSE for more details. """ -from flask import Blueprint, render_template, request, jsonify +import redis +from flask import Blueprint, render_template, request, jsonify, current_app, g +from rq import push_connection, pop_connection, Queue from .. import tasks from .forms import TaskForm bp = Blueprint('main', __name__) +def get_redis_connection(): + redis_connection = getattr(g, '_redis_connection', None) + if redis_connection is None: + redis_url = current_app.config['REDIS_URL'] + redis_connection = g._redis_connection = redis.from_url(redis_url) + return redis_connection + + +@bp.before_request +def push_rq_connection(): + push_connection(get_redis_connection()) + + +@bp.teardown_request +def pop_rq_connection(exception=None): + pop_connection() + + @bp.route('/_run_task', methods=['POST']) def run_task(): task = request.form.get('task') - try: - result = tasks.run(task) - except Exception as e: - return jsonify({'message': 'Task failed: {}'.format(e)}), 500 - return jsonify({'result': result}) + q = Queue() + job = q.enqueue(tasks.run, task) + return jsonify({'job_id': job.get_id()}) @bp.route('/') diff --git a/app/settings.py b/app/settings.py index 6a20aac..cd4035c 100644 --- a/app/settings.py +++ b/app/settings.py @@ -16,3 +16,5 @@ b'\x0c\x11{\xd3\x11$\xeeel\xa6\xfb\x1d~\xfd\xb3\x9d\x11\x00\xfb4\xd64\xd4\xe0') TASKS = ['Short task', 'Long task', 'Task raises error'] MAX_TIME_TO_WAIT = 10 +REDIS_URL = 'redis://redis:6379/0' +QUEUES = ['default'] diff --git a/app/static/js/main.js b/app/static/js/main.js index d3615da..91fd126 100644 --- a/app/static/js/main.js +++ b/app/static/js/main.js @@ -22,17 +22,17 @@ $(document).ready(function() { // submit form $("#submit").on('click', function() { - flash_alert("Running " + $("#task").val() + "...", "info"); + var task = $("#task").val(); $.ajax({ url: $SCRIPT_ROOT + "/_run_task", data: $("#taskForm").serialize(), method: "POST", dataType: "json", success: function(data) { - flash_alert(data.result, "success"); + flash_alert("Job " + data.job_id + " started...", "info", false); }, error: function(jqXHR, textStatus, errorThrown) { - flash_alert(JSON.parse(jqXHR.responseText).message, "danger"); + flash_alert("Failed to start " + task, "danger"); } }); }); diff --git a/docker-compose.yml b/docker-compose.yml index 6b23a0c..d614266 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,3 +11,17 @@ services: - "5000:5000" volumes: - .:/app + depends_on: + - redis + worker: + image: flaskrqexample + container_name: flaskrqexample_worker + environment: + LOCAL_SETTINGS: /app/settings.cfg + command: python manage.py runworker + volumes: + - .:/app + depends_on: + - redis + redis: + image: redis:3.2 diff --git a/environment.yml b/environment.yml index e7e36a6..b8c67b2 100644 --- a/environment.yml +++ b/environment.yml @@ -24,5 +24,7 @@ dependencies: - dominate==2.2.1 - flask-bootstrap==3.3.6.0 - flask-script==2.0.5 + - redis==2.10.5 + - rq==0.6.0 - visitor==0.1.3 diff --git a/manage.py b/manage.py index 9e363d1..fe86918 100644 --- a/manage.py +++ b/manage.py @@ -1,4 +1,6 @@ +import redis from flask_script import Server, Manager +from rq import Connection, Worker from uwsgi import app @@ -8,5 +10,14 @@ Server(port=5000, use_debugger=True, use_reloader=True)) +@manager.command +def runworker(): + redis_url = app.config['REDIS_URL'] + redis_connection = redis.from_url(redis_url) + with Connection(redis_connection): + worker = Worker(app.config['QUEUES']) + worker.work() + + if __name__ == '__main__': manager.run()