Skip to content

Commit

Permalink
finished
Browse files Browse the repository at this point in the history
  • Loading branch information
mjhea0 committed Oct 4, 2017
1 parent e36a50a commit 3fef150
Show file tree
Hide file tree
Showing 15 changed files with 212 additions and 98 deletions.
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM python:3.6.1

# set working directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# add requirements (to leverage Docker cache)
ADD ./requirements.txt /usr/src/app/requirements.txt

# install requirements
RUN pip install -r requirements.txt
36 changes: 4 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,12 @@

Example of how to handle background processes with Flask, Redis Queue, and Docker

## Quick Start
### Quick Start

### Basics

1. Create and activate a virtualenv
1. Install the requirements

### Set Environment Variables

Update *project/server/config.py*, and then run:
Spin up the containers:

```sh
$ export APP_SETTINGS="project.server.config.DevelopmentConfig"
$ docker-compose up -d
```

or

```sh
$ export APP_SETTINGS="project.server.config.ProductionConfig"
```

### Run the Application

```sh
$ python manage.py runserver
```

Access the application at the address [http://localhost:5000/](http://localhost:5000/)


### Test

Without coverage:

```sh
$ python manage.py test
```
Open your browser to http://localhost:5001
31 changes: 31 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: '2.1'

services:

web:
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
volumes:
- .:/usr/src/app
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
depends_on:
- redis

redis:
image: redis:3.2.11
10 changes: 10 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import os
import unittest

import redis
from rq import Connection, Worker
from flask_script import Manager

from project.server import app
Expand All @@ -22,5 +24,13 @@ def test():
return 1


@manager.command
def run_worker():
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()
18 changes: 15 additions & 3 deletions project/client/static/main.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
/* custom css */

.site-content {
padding-top: 75px;
}
html {
position: relative;
min-height: 100%;
}
body {
padding-top: 2rem;
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
height: 50px;
line-height: 50px;
}
43 changes: 41 additions & 2 deletions project/client/static/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
// custom javascript

$( document ).ready(function() {
$( document ).ready(() => {
console.log('Sanity Check!');
});
});

$('.btn').on('click', function() {
$.ajax({
url: '/tasks',
data: { type: $(this).data('type') },
method: 'POST'
})
.done((res) => {
getStatus(res.data.task_id)
})
.fail((err) => {
console.log(err)
})
})

function getStatus(taskID) {
$.ajax({
url: `/tasks/${taskID}`,
method: 'GET'
})
.done((res) => {
const html = `
<tr>
<td>${res.data.task_id}</td>
<td>${res.data.task_status}</td>
<td>${res.data.task_result}</td>
</tr>`
$('#tasks').prepend(html)
const taskStatus = res.data.task_status;
if (taskStatus === 'finished' || taskStatus === 'failed') return false;
setTimeout(function() {
getStatus(res.data.task_id);
}, 1000);
})
.fail((err) => {
console.log(err)
})
}

49 changes: 9 additions & 40 deletions project/client/templates/_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,33 @@

<head>
<meta charset="utf-8">
<title>Flask Skeleton{% block title %}{% endblock %}</title>
<title>Flask + Redis Queue + Docker{% block title %}{% endblock %}</title>
<!-- meta -->
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width,initial-scale=1">
<!-- styles -->
<link href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.1/yeti/bootstrap.min.css" rel="stylesheet" media="screen">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css">
<link href="{{url_for('static', filename='main.css')}}" rel="stylesheet" media="screen">
{% block css %}{% endblock %}
</head>

<body>

{% include 'header.html' %}

<div class="site-content">
<div class="container">

<!-- messages -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<br>
<div class="row">
<div class="col-md-12">
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
<a class="close" title="Close" href="#" data-dismiss="alert">&times;</a>
{{message}}
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endwith %}


<!-- child template -->
{% block content %}{% endblock %}

<br>

<!-- errors -->
{% if error %}
<p class="error"><strong>Error:</strong> {{ error }}</p>
{% endif %}

</div>
<div class="container">
<!-- child template -->
{% block content %}{% endblock %}
</div>

<br><br>

{% include 'footer.html' %}

<!-- scripts -->
<script src="//code.jquery.com/jquery-1.11.2.min.js" type="text/javascript"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js" type="text/javascript"></script>
<script src="//code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"></script>
<script src="{{url_for('static', filename='main.js')}}" type="text/javascript"></script>
{% block js %}{% endblock %}

</body>

</html>
6 changes: 2 additions & 4 deletions project/client/templates/footer.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<footer>
<footer class="footer">
<div class="container">
<small>
<span>© <a href="http://mherman.org">Michael Herman</a></span>
</small>
<small><span class="text-muted">© <a href="http://mherman.org">Michael Herman</a></span></small>
</div>
</footer>
9 changes: 0 additions & 9 deletions project/client/templates/header.html

This file was deleted.

31 changes: 28 additions & 3 deletions project/client/templates/main/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,34 @@

{% block content %}

<div class="body-content">
<div class="row">
<h1>Welcome!</h1>
<div class="starter-template">
<h1>Flask + Redis Queue + Docker</h1>
<hr><br>
<div>
<h3>Tasks</h3>
<p>Pick a task length...</p>
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-primary" data-type="1">Short</a>
<button type="button" class="btn btn-primary" data-type="2">Medium</a>
<button type="button" class="btn btn-primary" data-type="3">Long</a>
</div>
</div>
<br><br>
<div>
<h3>Task Status</h3>
<br>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Status</th>
<th>Result</th>
</tr>
</thead>
<tbody id="tasks">
</tbody>
</table>
</div>
</div>
</div>

Expand Down
3 changes: 2 additions & 1 deletion project/server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class BaseConfig(object):
"""Base configuration."""
DEBUG = False
WTF_CSRF_ENABLED = True

REDIS_URL = 'redis://redis:6379/0'
QUEUES = ['default']

class DevelopmentConfig(BaseConfig):
"""Development configuration."""
Expand Down
9 changes: 9 additions & 0 deletions project/server/main/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# project/server/main/tasks.py


import time


def create_task(task_type):
time.sleep(int(task_type) * 10)
return True
49 changes: 47 additions & 2 deletions project/server/main/views.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,57 @@
# project/server/main/views.py


from flask import render_template, Blueprint
import redis
from rq import Queue, push_connection, pop_connection
from flask import current_app, render_template, Blueprint, jsonify, request

from project.server.main.tasks import create_task

main_blueprint = Blueprint('main', __name__,)


@main_blueprint.route('/')
@main_blueprint.route('/', methods=['GET'])
def home():
return render_template('main/home.html')


@main_blueprint.route('/tasks', methods=['POST'])
def run_task():
task_type = request.form['type']
q = Queue()
task = q.enqueue(create_task, task_type)
response_object = {
'status': 'success',
'data': {
'task_id': task.get_id()
}
}
return jsonify(response_object), 202


@main_blueprint.route('/tasks/<task_id>', methods=['GET'])
def get_status(task_id):
q = Queue()
task = q.fetch_job(task_id)
if task:
response_object = {
'status': 'success',
'data': {
'task_id': task.get_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()
Loading

0 comments on commit 3fef150

Please sign in to comment.