1660170780
Se uma tarefa de longa duração fizer parte do fluxo de trabalho do seu aplicativo, você deve tratá-la em segundo plano, fora do fluxo normal.
Talvez seu aplicativo da web exija que os usuários enviem uma miniatura (que provavelmente precisará ser redimensionada) e confirme seu e-mail quando se registrarem. Se seu aplicativo processou a imagem e enviou um e-mail de confirmação diretamente no manipulador de solicitação, o usuário final teria que esperar que ambos terminassem. Em vez disso, você desejará passar essas tarefas para uma fila de tarefas e deixar que um processo de trabalho separado lide com isso, para que você possa enviar imediatamente uma resposta de volta ao cliente. O usuário final pode fazer outras coisas no lado do cliente e seu aplicativo fica livre para responder às solicitações de outros usuários.
Este tutorial analisa como configurar o Redis Queue (RQ) para lidar com tarefas de longa duração em um aplicativo Flask.
Ao final deste tutorial, você será capaz de:
Nosso objetivo é desenvolver um aplicativo Flask que funcione em conjunto com o Redis Queue para lidar com processos de longa execução fora do ciclo normal de solicitação/resposta.
No final, o aplicativo ficará assim:
Quer acompanhar? Clone o projeto base e revise o código e a estrutura do projeto:
$ git clone https://github.com/mjhea0/flask-redis-queue --branch base --single-branch
$ cd flask-redis-queue
Como precisaremos gerenciar três processos no total (Flask, Redis, worker), usaremos o Docker para simplificar nosso fluxo de trabalho para que eles possam ser gerenciados em uma única janela de terminal.
Para testar, execute:
$ docker-compose up -d --build
Abra seu navegador para http://localhost:5004 . Você deveria ver:
Um manipulador de eventos em project/client/static/main.js é configurado para escutar um clique de botão e enviar uma solicitação POST AJAX para o servidor com o tipo de tarefa apropriado: 1
, 2
ou 3
.
$('.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);
});
});
No lado do servidor, uma visualização já está configurada para lidar com a solicitação em project/server/main/views.py :
@main_blueprint.route("/tasks", methods=["POST"])
def run_task():
task_type = request.form["type"]
return jsonify(task_type), 202
Só precisamos conectar o Redis Queue.
Então, precisamos criar dois novos processos: Redis e um trabalhador. Adicione-os ao arquivo docker-compose.yml :
version: '3.8'
services:
web:
build: .
image: web
container_name: web
ports:
- 5004:5000
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
command: python manage.py run_worker
volumes:
- .:/usr/src/app
environment:
- APP_SETTINGS=project.server.config.DevelopmentConfig
depends_on:
- redis
redis:
image: redis:6.2-alpine
Adicione a tarefa a um novo arquivo chamado tasks.py em "project/server/main":
# project/server/main/tasks.py
import time
def create_task(task_type):
time.sleep(int(task_type) * 10)
return True
Atualize a visualização para se conectar ao Redis, enfileirar a tarefa e responder com o id:
@main_blueprint.route("/tasks", methods=["POST"])
def run_task():
task_type = request.form["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": {
"task_id": task.get_id()
}
}
return jsonify(response_object), 202
Não esqueça das importações:
import redis
from rq import Queue, Connection
from flask import render_template, Blueprint, jsonify, request, current_app
from project.server.main.tasks import create_task
Atualização BaseConfig
:
class BaseConfig(object):
"""Base configuration."""
WTF_CSRF_ENABLED = True
REDIS_URL = "redis://redis:6379/0"
QUEUES = ["default"]
Você notou que referenciamos o redis
serviço (de docker-compose.yml ) em REDIS_URL
vez de localhost
ou em algum outro IP? Revise os documentos do Docker Compose para obter mais informações sobre como se conectar a outros serviços por meio do nome do host.
Por fim, podemos usar um Redis Queue worker , para processar tarefas no topo da fila.
gerencie.py :
@cli.command("run_worker")
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()
Aqui, configuramos um comando CLI personalizado para acionar o trabalhador.
É importante observar que o @cli.command()
decorador fornecerá acesso ao contexto do aplicativo junto com as variáveis de configuração associadas de project/server/config.py quando o comando for executado.
Adicione as importações também:
import redis
from rq import Connection, Worker
Adicione as dependências ao arquivo de requisitos:
redis==4.1.1
rq==1.10.1
Construa e gire os novos contêineres:
$ docker-compose up -d --build
Para acionar uma nova tarefa, execute:
$ curl -F type=0 http://localhost:5004/tasks
Você deve ver algo como:
{
"data": {
"task_id": "bdad64d0-3865-430e-9cc3-ec1410ddb0fd"
},
"status": "success"
}
Volte para o manipulador de eventos no lado do cliente:
$('.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);
});
});
Depois que a resposta voltar da solicitação AJAX original, continuamos a chamar getStatus()
com o ID da tarefa a cada segundo. Se a resposta for bem-sucedida, uma nova linha será adicionada à tabela no DOM.
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);
});
}
Atualize a visualização:
@main_blueprint.route("/tasks/<task_id>", methods=["GET"])
def get_status(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",
"data": {
"task_id": task.get_id(),
"task_status": task.get_status(),
"task_result": task.result,
},
}
else:
response_object = {"status": "error"}
return jsonify(response_object)
Adicione uma nova tarefa à fila:
$ curl -F type=1 http://localhost:5004/tasks
Em seguida, pegue o task_id
da resposta e chame o endpoint atualizado para visualizar o status:
$ curl http://localhost:5004/tasks/5819789f-ebd7-4e67-afc3-5621c28acf02
{
"data": {
"task_id": "5819789f-ebd7-4e67-afc3-5621c28acf02",
"task_result": true,
"task_status": "finished"
},
"status": "success"
}
Teste também no navegador:
O RQ Dashboard é um sistema de monitoramento leve e baseado na Web para Redis Queue.
Para configurar, primeiro adicione um novo diretório ao diretório "project" chamado "dashboard". Em seguida, adicione um novo Dockerfile a esse diretório recém-criado:
FROM python:3.10-alpine
RUN pip install rq-dashboard
# https://github.com/rq/rq/issues/1469
RUN pip uninstall -y click
RUN pip install click==7.1.2
EXPOSE 9181
CMD ["rq-dashboard"]
Basta adicionar o serviço ao arquivo docker-compose.yml assim:
version: '3.8'
services:
web:
build: .
image: web
container_name: web
ports:
- 5004:5000
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
command: python manage.py run_worker
volumes:
- .:/usr/src/app
environment:
- APP_SETTINGS=project.server.config.DevelopmentConfig
depends_on:
- redis
redis:
image: redis:6.2-alpine
dashboard:
build: ./project/dashboard
image: dashboard
container_name: dashboard
ports:
- 9181:9181
command: rq-dashboard -H redis
depends_on:
- redis
Construa a imagem e gire o contêiner:
$ docker-compose up -d --build
Navegue até http://localhost:9181 para visualizar o painel:
Dê início a alguns trabalhos para testar completamente o painel:
Tente adicionar mais alguns trabalhadores para ver como isso afeta as coisas:
$ docker-compose up -d --build --scale worker=3
Este foi um guia básico sobre como configurar o Redis Queue para executar tarefas de longa duração em um aplicativo Flask. Você deve deixar a fila lidar com quaisquer processos que possam bloquear ou retardar o código voltado para o usuário.
Pegue o código do repositório .
Fonte: https://testdrive.io
1660170780
Se uma tarefa de longa duração fizer parte do fluxo de trabalho do seu aplicativo, você deve tratá-la em segundo plano, fora do fluxo normal.
Talvez seu aplicativo da web exija que os usuários enviem uma miniatura (que provavelmente precisará ser redimensionada) e confirme seu e-mail quando se registrarem. Se seu aplicativo processou a imagem e enviou um e-mail de confirmação diretamente no manipulador de solicitação, o usuário final teria que esperar que ambos terminassem. Em vez disso, você desejará passar essas tarefas para uma fila de tarefas e deixar que um processo de trabalho separado lide com isso, para que você possa enviar imediatamente uma resposta de volta ao cliente. O usuário final pode fazer outras coisas no lado do cliente e seu aplicativo fica livre para responder às solicitações de outros usuários.
Este tutorial analisa como configurar o Redis Queue (RQ) para lidar com tarefas de longa duração em um aplicativo Flask.
Ao final deste tutorial, você será capaz de:
Nosso objetivo é desenvolver um aplicativo Flask que funcione em conjunto com o Redis Queue para lidar com processos de longa execução fora do ciclo normal de solicitação/resposta.
No final, o aplicativo ficará assim:
Quer acompanhar? Clone o projeto base e revise o código e a estrutura do projeto:
$ git clone https://github.com/mjhea0/flask-redis-queue --branch base --single-branch
$ cd flask-redis-queue
Como precisaremos gerenciar três processos no total (Flask, Redis, worker), usaremos o Docker para simplificar nosso fluxo de trabalho para que eles possam ser gerenciados em uma única janela de terminal.
Para testar, execute:
$ docker-compose up -d --build
Abra seu navegador para http://localhost:5004 . Você deveria ver:
Um manipulador de eventos em project/client/static/main.js é configurado para escutar um clique de botão e enviar uma solicitação POST AJAX para o servidor com o tipo de tarefa apropriado: 1
, 2
ou 3
.
$('.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);
});
});
No lado do servidor, uma visualização já está configurada para lidar com a solicitação em project/server/main/views.py :
@main_blueprint.route("/tasks", methods=["POST"])
def run_task():
task_type = request.form["type"]
return jsonify(task_type), 202
Só precisamos conectar o Redis Queue.
Então, precisamos criar dois novos processos: Redis e um trabalhador. Adicione-os ao arquivo docker-compose.yml :
version: '3.8'
services:
web:
build: .
image: web
container_name: web
ports:
- 5004:5000
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
command: python manage.py run_worker
volumes:
- .:/usr/src/app
environment:
- APP_SETTINGS=project.server.config.DevelopmentConfig
depends_on:
- redis
redis:
image: redis:6.2-alpine
Adicione a tarefa a um novo arquivo chamado tasks.py em "project/server/main":
# project/server/main/tasks.py
import time
def create_task(task_type):
time.sleep(int(task_type) * 10)
return True
Atualize a visualização para se conectar ao Redis, enfileirar a tarefa e responder com o id:
@main_blueprint.route("/tasks", methods=["POST"])
def run_task():
task_type = request.form["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": {
"task_id": task.get_id()
}
}
return jsonify(response_object), 202
Não esqueça das importações:
import redis
from rq import Queue, Connection
from flask import render_template, Blueprint, jsonify, request, current_app
from project.server.main.tasks import create_task
Atualização BaseConfig
:
class BaseConfig(object):
"""Base configuration."""
WTF_CSRF_ENABLED = True
REDIS_URL = "redis://redis:6379/0"
QUEUES = ["default"]
Você notou que referenciamos o redis
serviço (de docker-compose.yml ) em REDIS_URL
vez de localhost
ou em algum outro IP? Revise os documentos do Docker Compose para obter mais informações sobre como se conectar a outros serviços por meio do nome do host.
Por fim, podemos usar um Redis Queue worker , para processar tarefas no topo da fila.
gerencie.py :
@cli.command("run_worker")
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()
Aqui, configuramos um comando CLI personalizado para acionar o trabalhador.
É importante observar que o @cli.command()
decorador fornecerá acesso ao contexto do aplicativo junto com as variáveis de configuração associadas de project/server/config.py quando o comando for executado.
Adicione as importações também:
import redis
from rq import Connection, Worker
Adicione as dependências ao arquivo de requisitos:
redis==4.1.1
rq==1.10.1
Construa e gire os novos contêineres:
$ docker-compose up -d --build
Para acionar uma nova tarefa, execute:
$ curl -F type=0 http://localhost:5004/tasks
Você deve ver algo como:
{
"data": {
"task_id": "bdad64d0-3865-430e-9cc3-ec1410ddb0fd"
},
"status": "success"
}
Volte para o manipulador de eventos no lado do cliente:
$('.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);
});
});
Depois que a resposta voltar da solicitação AJAX original, continuamos a chamar getStatus()
com o ID da tarefa a cada segundo. Se a resposta for bem-sucedida, uma nova linha será adicionada à tabela no DOM.
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);
});
}
Atualize a visualização:
@main_blueprint.route("/tasks/<task_id>", methods=["GET"])
def get_status(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",
"data": {
"task_id": task.get_id(),
"task_status": task.get_status(),
"task_result": task.result,
},
}
else:
response_object = {"status": "error"}
return jsonify(response_object)
Adicione uma nova tarefa à fila:
$ curl -F type=1 http://localhost:5004/tasks
Em seguida, pegue o task_id
da resposta e chame o endpoint atualizado para visualizar o status:
$ curl http://localhost:5004/tasks/5819789f-ebd7-4e67-afc3-5621c28acf02
{
"data": {
"task_id": "5819789f-ebd7-4e67-afc3-5621c28acf02",
"task_result": true,
"task_status": "finished"
},
"status": "success"
}
Teste também no navegador:
O RQ Dashboard é um sistema de monitoramento leve e baseado na Web para Redis Queue.
Para configurar, primeiro adicione um novo diretório ao diretório "project" chamado "dashboard". Em seguida, adicione um novo Dockerfile a esse diretório recém-criado:
FROM python:3.10-alpine
RUN pip install rq-dashboard
# https://github.com/rq/rq/issues/1469
RUN pip uninstall -y click
RUN pip install click==7.1.2
EXPOSE 9181
CMD ["rq-dashboard"]
Basta adicionar o serviço ao arquivo docker-compose.yml assim:
version: '3.8'
services:
web:
build: .
image: web
container_name: web
ports:
- 5004:5000
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
command: python manage.py run_worker
volumes:
- .:/usr/src/app
environment:
- APP_SETTINGS=project.server.config.DevelopmentConfig
depends_on:
- redis
redis:
image: redis:6.2-alpine
dashboard:
build: ./project/dashboard
image: dashboard
container_name: dashboard
ports:
- 9181:9181
command: rq-dashboard -H redis
depends_on:
- redis
Construa a imagem e gire o contêiner:
$ docker-compose up -d --build
Navegue até http://localhost:9181 para visualizar o painel:
Dê início a alguns trabalhos para testar completamente o painel:
Tente adicionar mais alguns trabalhadores para ver como isso afeta as coisas:
$ docker-compose up -d --build --scale worker=3
Este foi um guia básico sobre como configurar o Redis Queue para executar tarefas de longa duração em um aplicativo Flask. Você deve deixar a fila lidar com quaisquer processos que possam bloquear ou retardar o código voltado para o usuário.
Pegue o código do repositório .
Fonte: https://testdrive.io
1596679140
Redis offers two mechanisms for handling transactions – MULTI/EXEC based transactions and Lua scripts evaluation. Redis Lua scripting is the recommended approach and is fairly popular in usage.
Our Redis™ customers who have Lua scripts deployed often report this error – “BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE”. In this post, we will explain the Redis transactional property of scripts, what this error is about, and why we must be extra careful about it on Sentinel-managed systems that can failover.
Redis “transactions” aren’t really transactions as understood conventionally – in case of errors, there is no rollback of writes made by the script.
“Atomicity” of Redis scripts is guaranteed in the following manner:
It is highly recommended that the script complete within a time limit. Redis enforces this in a weak manner with the ‘lua-time-limit’ value. This is the maximum allowed time (in ms) that the script is allowed to run. The default value is 5 seconds. This is a really long time for CPU-bound activity (scripts have limited access and can’t run commands that access the disk).
However, the script is not killed when it executes beyond this time. Redis starts accepting client commands again, but responds to them with a BUSY error.
If you must kill the script at this point, there are two options available:
It is usually better to just wait for the script to complete its operation. The complete information on methods to kill the script execution and related behavior are available in the documentation.
#cloud #database #developer #high availability #howto #redis #scalegrid #lua-time-limit #redis diagram #redis master #redis scripts #redis sentinel #redis servers #redis transactions #sentinel-managed #server failures
1668680340
If a long-running task is part of your application's workflow you should handle it in the background, outside the normal flow.
Perhaps your web application requires users to submit a thumbnail (which will probably need to be re-sized) and confirm their email when they register. If your application processed the image and sent a confirmation email directly in the request handler, then the end user would have to wait for them both to finish. Instead, you'll want to pass these tasks off to a task queue and let a separate worker process deal with it, so you can immediately send a response back to the client. The end user can do other things on the client-side and your application is free to respond to requests from other users.
This tutorial looks at how to configure Redis Queue (RQ) to handle long-running tasks in a Flask app.
Celery is a viable solution as well. Check out Asynchronous Tasks with Flask and Celery for more.
By the end of this tutorial, you will be able to:
Our goal is to develop a Flask application that works in conjunction with Redis Queue to handle long-running processes outside the normal request/response cycle.
In the end, the app will look like this:
Want to follow along? Clone down the base project, and then review the code and project structure:
$ git clone https://github.com/mjhea0/flask-redis-queue --branch base --single-branch
$ cd flask-redis-queue
Since we'll need to manage three processes in total (Flask, Redis, worker), we'll use Docker to simplify our workflow so they can be managed from a single terminal window.
To test, run:
$ docker-compose up -d --build
Open your browser to http://localhost:5004. You should see:
An event handler in project/client/static/main.js is set up that listens for a button click and sends an AJAX POST request to the server with the appropriate task type: 1
, 2
, or 3
.
$('.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);
});
});
On the server-side, a view is already configured to handle the request in project/server/main/views.py:
@main_blueprint.route("/tasks", methods=["POST"])
def run_task():
task_type = request.form["type"]
return jsonify(task_type), 202
We just need to wire up Redis Queue.
So, we need to spin up two new processes: Redis and a worker. Add them to the docker-compose.yml file:
version: '3.8'
services:
web:
build: .
image: web
container_name: web
ports:
- 5004:5000
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
command: python manage.py run_worker
volumes:
- .:/usr/src/app
environment:
- APP_SETTINGS=project.server.config.DevelopmentConfig
depends_on:
- redis
redis:
image: redis:6.2-alpine
Add the task to a new file called tasks.py in "project/server/main":
# project/server/main/tasks.py
import time
def create_task(task_type):
time.sleep(int(task_type) * 10)
return True
Update the view to connect to Redis, enqueue the task, and respond with the id:
@main_blueprint.route("/tasks", methods=["POST"])
def run_task():
task_type = request.form["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": {
"task_id": task.get_id()
}
}
return jsonify(response_object), 202
Don't forget the imports:
import redis
from rq import Queue, Connection
from flask import render_template, Blueprint, jsonify, request, current_app
from project.server.main.tasks import create_task
Update BaseConfig
:
class BaseConfig(object):
"""Base configuration."""
WTF_CSRF_ENABLED = True
REDIS_URL = "redis://redis:6379/0"
QUEUES = ["default"]
Did you notice that we referenced the redis
service (from docker-compose.yml) in the REDIS_URL
rather than localhost
or some other IP? Review the Docker Compose docs for more info on connecting to other services via the hostname.
Finally, we can use a Redis Queue worker, to process tasks at the top of the queue.
manage.py:
@cli.command("run_worker")
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()
Here, we set up a custom CLI command to fire the worker.
It's important to note that the @cli.command()
decorator will provide access to the application context along with the associated config variables from project/server/config.py when the command is executed.
Add the imports as well:
import redis
from rq import Connection, Worker
Add the dependencies to the requirements file:
redis==4.1.1
rq==1.10.1
Build and spin up the new containers:
$ docker-compose up -d --build
To trigger a new task, run:
$ curl -F type=0 http://localhost:5004/tasks
You should see something like:
{
"data": {
"task_id": "bdad64d0-3865-430e-9cc3-ec1410ddb0fd"
},
"status": "success"
}
Turn back to the event handler on the client-side:
$('.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);
});
});
Once the response comes back from the original AJAX request, we then continue to call getStatus()
with the task id every second. If the response is successful, a new row is added to the table on the DOM.
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);
});
}
Update the view:
@main_blueprint.route("/tasks/<task_id>", methods=["GET"])
def get_status(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",
"data": {
"task_id": task.get_id(),
"task_status": task.get_status(),
"task_result": task.result,
},
}
else:
response_object = {"status": "error"}
return jsonify(response_object)
Add a new task to the queue:
$ curl -F type=1 http://localhost:5004/tasks
Then, grab the task_id
from the response and call the updated endpoint to view the status:
$ curl http://localhost:5004/tasks/5819789f-ebd7-4e67-afc3-5621c28acf02
{
"data": {
"task_id": "5819789f-ebd7-4e67-afc3-5621c28acf02",
"task_result": true,
"task_status": "finished"
},
"status": "success"
}
Test it out in the browser as well:
RQ Dashboard is a lightweight, web-based monitoring system for Redis Queue.
To set up, first add a new directory to the "project" directory called "dashboard". Then, add a new Dockerfile to that newly created directory:
FROM python:3.10-alpine
RUN pip install rq-dashboard
# https://github.com/rq/rq/issues/1469
RUN pip uninstall -y click
RUN pip install click==7.1.2
EXPOSE 9181
CMD ["rq-dashboard"]
Simply add the service to the docker-compose.yml file like so:
version: '3.8'
services:
web:
build: .
image: web
container_name: web
ports:
- 5004:5000
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
command: python manage.py run_worker
volumes:
- .:/usr/src/app
environment:
- APP_SETTINGS=project.server.config.DevelopmentConfig
depends_on:
- redis
redis:
image: redis:6.2-alpine
dashboard:
build: ./project/dashboard
image: dashboard
container_name: dashboard
ports:
- 9181:9181
command: rq-dashboard -H redis
depends_on:
- redis
Build the image and spin up the container:
$ docker-compose up -d --build
Navigate to http://localhost:9181 to view the dashboard:
Kick off a few jobs to fully test the dashboard:
Try adding a few more workers to see how that affects things:
$ docker-compose up -d --build --scale worker=3
This has been a basic guide on how to configure Redis Queue to run long-running tasks in a Flask app. You should let the queue handle any processes that could block or slow down the user-facing code.
Looking for some challenges?
Grab the code from the repo.
Original article source at: https://testdriven.io/
1618254581
geeksquad.com/chat-with-an-agent
walmart.capitalone.com/activate
#netflix.com/activate #roku.com/link #amazon.com/mytv #primevideo.com/mytv #samsung.com/printersetup
1611609121
Pay Medical Bills your bills @https://sites.google.com/view/www-quickpayportal-com/
It is really very easy to pay your bills at [priviabillpay.com](https://sites.google.com/view/www-quickpayportal-com/ "priviabillpay.com"). First of all, patients will have to go to the official Privia Medical Community Online portal . Patients can use the quick pay code of priviabillpay.com to make a one-time payment. On the first page of your statement, the QuickPay code is found. Using Priviabillpay to follow a few steps to get paid.
First of all, you must visit the official portal at [www.priviabillpay.com](https://sites.google.com/view/www-quickpayportal-com/ "www.priviabillpay.com")
In the box, fill out the QuickPay Code and tap Make a Payment.
You will be redirected to a page showing all your current rates.
Now select the fees you want to pay and click the check box that you want to accept quickly.
Finally, click on the payment option button.
Your payment details will be asked on the screen.
Fill out the field required and submit your payment.
Our Official Website : https://sites.google.com/view/www-quickpayportal-com/
#www.priviabillpay.com #www-quickpayportal-com #quickpayportal.com #www.quickpayportal.com. #quickpayportal.com.