- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在 Django 应用程序中,我正在运行异步任务,并希望向用户显示进度、错误等。如果有错误,用户应该被重定向到一个页面,在该页面上需要额外的输入或一些操作来解决问题。从 celery 工作返回到前端的最佳通信方式是什么?
这是伪代码的基本结构:
# views.py
from tasks import run_task
def view_task():
run_task.delay()
return render(request, 'template.html')
# tasks.py
from compute_module import compute_fct
@shared_task
def run_task():
result = compute_fct()
# how to catch status update messages from compute_module while compute_fct is running??
if result == 'error':
handle_error()
else:
handle_succes()
# compute_module
import pandas as pd
def compute_fct():
# send message: status = loading file
df = pd.read_csv('test.csv')
# send message: status = computing
val = df['col'].mean()
if val is None:
return {'status':'error'}
else:
return {'status':'success','val':val}
理想情况下我想要什么:
compute_module.py
模块使用 python 原生记录器。通过职责分离,我希望尽可能保持日志记录的通用性,并使用标准的 python/django 记录器。但它们似乎并不是为了向前端发送消息而设计的。 在 celery worker 和前端之间可能存在我不知道的标准通信方式。这种情况一定经常发生,我很惊讶它如此难以实现。在某种程度上,rabbitmq 消息队列或 aws sns 应该为此设计。以下是我看过的资源,但我觉得它们中的任何一个都不是很好,但也许我只是感到困惑。
日志记录:这似乎更多是关于在服务器端进行日志记录,而不是向用户发送消息
Celery cam 似乎是关于管理员监控任务,而不是向用户发送消息
pusher 我喜欢,但我不想让 compute_module.py
处理它。例如,我不希望在 compute_module.py
中进行任何 pusher.com 集成。我想我可以传递一个已经实例化的推送器对象,这样模块就可以推送消息,但我还是希望它是通用的
最佳答案
编辑:现在转移到 django-channels,效果很好但比下面的解决方案更复杂。
上一个:
好的,下面是我目前如何解决它的伪代码。基本上我使用 https://pusher.com/docs/javascript_quick_start服务器端将实例化对象传递到 compute_module
。一个缺点是推送消息是短暂的,所以我将不得不在 LogPusher
中做一些额外的工作以将它们存储在数据库中,改天再做......
同样在我的实际实现中,我通过 $(document).ready()
中的 $.post()
ajax 调用触发任务,因为小任务完成得非常快用户永远不会看到推送消息,因为未建立连接(回到那个历史消息问题)。
我上面没有提到的另一个替代路线是 https://channels.readthedocs.io/en/latest/
[编辑] 另一个解决方案是 Server-sent events其中有 django implementations ,还没有测试过。但它看起来很适合单向更新,例如从服务器到客户端(相对于 websockets 双向)。你需要一个像redis pubsub这样的消息系统获取服务器 sse 路由的更新。
通过推送器从 django 服务器进行前端更新:
# views.py
from tasks import run_task
def view_task():
run_task.delay('event')
return render(request, 'template.html', 'pusher_event':'event')
# tasks.py
import pusher
from django.conf import settings
from compute_module import compute_fct
class LogPusher(object):
def __init__(self, event):
self.pusher_client = pusher.Pusher(app_id=settings.PUSHER_APP_ID,
key=settings.PUSHER_KEY,
secret=settings.PUSHER_SECRET,
cluster=settings.PUSHER_CLUSTER, ssl=True)
self.event = event
def send(self, data):
self.pusher_client.trigger(settings.PUSHER_CHANNEL, self.event, json.dumps(data))
@shared_task
def run_task(pusher_event):
log_pusher = LogPusher(pusher_event)
result = compute_fct(log_pusher)
# how to catch status update messages from compute_module while compute_fct is running??
if result == 'error':
log_pusher.send('status':'error')
else:
log_pusher.send('status':'success')
# compute_module.py
import pandas as pd
def compute_fct(log_pusher):
# send message: status = loading file
log_pusher.send('status':'loading file')
df = pd.read_csv('test.csv')
# send message: status = computing
log_pusher.send('status':'computing')
val = df['col'].mean()
if val is None:
return {'status':'error'}
else:
return {'status':'success','val':val}
# context_processors.py
# see https://stackoverflow.com/questions/433162/can-i-access-constants-in-settings-py-from-templates-in-django
from django.conf import settings
def pusher(request):
return {'PUSHER_KEY': settings.PUSHER_KEY, 'PUSHER_CLUSTER': settings.PUSHER_CLUSTER , 'PUSHER_CHANNEL': settings.PUSHER_CHANNEL }
# template.html
<script>
var pusher = new Pusher("{{PUSHER_KEY}}", {
cluster: "{{PUSHER_CLUSTER}}",
encrypted: true
});
var channel = pusher.subscribe("{{PUSHER_CHANNEL}}");
channel.bind("{{pusher_event}}", function(data) {
// process data
});
</script>
关于python - Django celery worker 向前端发送实时状态和结果消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47841809/
我对 Python-Django 和 web 开发还很陌生,我被困在这个使用 POST 创建新资源的特殊问题上。 我正在为 REST API 使用 Django REST 框架,我正在尝试创建一个新资
我已经使用 Django-storages 成功地将 Word 文档存储到 S3。 class Document(TitleSlugDescriptionModel, TimeStampedModel
我有 2 个关于模型代理的问题, 如何从模型对象创建代理对象? 如何从模型查询集创建代理查询集? 例如,假设我们定义了: from django.contrib.auth.models import
我想编写一个直接执行 HTTP 请求的单元测试(而不是使用 django.test.client.Client)。 如果您好奇为什么 - 那是因为我想测试我从 Django 应用程序公开的 Thrif
我为我的个人网站启动了一个 django 项目来学习 django。到目前为止,我已经将我的开发环境设置为我需要的一切,并遵循 this很棒的教程来创建一些基本的数据结构和模板。现在我想开始使用我之前
我已经阅读了很多关于如何在使用 Django 注册时添加额外字段的信息,例如 here 、 here 和 here 。代码片段是: forms.py(来自注册应用程序) class Registrat
我正在编写小型社交应用程序。功能之一是在网站标题中写入用户名。因此,例如,如果我登录并且我的名字是Oleg(用户名),那么我应该看到: Hello, Oleg | Click to edit prof
我有一个使用 Django 和 Django Rest 框架开发的应用程序。我想将 django-reversion 功能添加到我的应用程序中。 我已经尝试过http://django-reversi
我有一个简单的 HTML 表单,我没有使用 Django 表单,但现在我想添加一个选择。 选择最容易创建为 Django ChoiceField (与通过循环等手动创建选择相反),但是,如果没有在 D
我不明白为什么人们以两种方式编写外键,这样做的目的是什么?它们是相同还是不同? 我注意到有些人这样写: author = models.ForeignKey(Author, on_delete=mod
我想在我的 Django 应用程序中获取评论最多的十个帖子,但我做不到,因为我想不出合适的方法。 我目前正在使用 django 评论框架,并且我已经看到使用 aggregate or annotate
这对于 Django 1.2 仍然有效吗? Custom Filter in Django Admin on Django 1.3 or below 我已经尝试过,但管理类中的 list_filter
问题在于,当 django-compressor 编译为 .js 文件的 CoffeeScript 文件中引用 {{ STATIC_URL }} 时,它无法正确加载。 在我的 django 模板中,我
我正在尝试将一些字段从一个 django 模型移动到一个新模型。假设我有一个书籍模型: class Book(models.Model): title = models.CharField(max
我想在我的 Django 应用程序中获取评论最多的十个帖子,但我做不到,因为我想不出合适的方法。 我目前正在使用 django 评论框架,并且我已经看到使用 aggregate or annotate
目前我正在寻找在 Django 中实现访问控制。我已经阅读了有关内置权限的内容,但它并不关心每个对象的基础。例如,我想要“只有创建者可以删除自己的项目”之类的权限。所以我读到了 django-guar
嗨,我正在将我的 Django 模型的一个字段的值设置为其他模型的另一个字段的值。这个值应该是动态变化的。 这是我的第一个模型 class MainModel(AbstractBaseUser, Pe
我正在尝试为我的模型创建一个编辑表单。我没有使用模型表单,因为根据模型类型,用户可以使用不同的表单。 (例如,其中一个表单有 Tinymce 小部件,而另一个没有。) 有没有什么方法可以使用模型设置表
Django 模板中的搜索字段 如何在类似于此图像的 Django 模板中创建搜索字段 http://asciicasts.com/system/photos/1204/original/E354I0
根据 Django documentation ,如果 Django 安装激活了 AuthenticationMiddleware,HttpRequest 对象有一个“user”属性代表当前登录的用户
我是一名优秀的程序员,十分优秀!