我正在建立一个工作的内部工具,只是为了让一些人的生活更轻松。该任务涉及CSV作为输入,它将被处理并生成新文件。该部分已经完成,我制作了一个可行的命令行脚本。但我希望尽可能使其易于访问,因此Web UI是一种自然的选择。我玩了一点烧瓶,用它制作了另一个简单的内部工具,我也想用这个做同样的工具。
我有这个脚本可能需要一段时间来处理文件,有时几分钟。这意味着我希望在Web UI中使其无阻塞。理想情况下,用户选择文件,选择几个选项命中提交,作业在后台启动。应该有一个进度条来向用户显示完成的时间。我不打算在这里进行用户管理,但是任何人都可以查看任何人触发的所有工作的列表。作业完成后,应该有一个链接来下载处理过的文件。
从我读过的内容来看,这是一种任务排队系统与消息代理一起使用的情况,如Celery和Redis。我已经阅读了一些有关此问题的教程,但我仍然不确定该怎么做...从哪里开始?什么是这类问题的最佳架构?另外,如何最好地处理上传部分,也许使用ajax?
如果可能的话,我正在寻找一些建议,参考和代码示例。任何与我想做的事情有关的例子都表示赞赏。
答案 0 :(得分:5)
根据您发布的内容,您似乎走在了正确的轨道上。您正在努力实现的是将资源需求高的任务卸载到"存根工作者"让您的网络专注于向您的用户展示。
您希望使用的模式通常被称为"发布/订阅"图案:
您的申请将发布"发布" Celery任务进入消息代理(Rabbit MQ)。您的Celery任务工作人员将"订阅"到消息代理并查找要执行的任务。非常简单的模式。
考虑到你使用的标签,我会假设你熟悉Flask(伟大的微框架),我建议你看看" Flask-Uploads"为了您的上传需求。
为了处理您的CSV文件,需要创建函数本身并使用@task
装饰器将其包装起来,让Celery将其识别为任务。使用了一些" Google-fu",我遇到了这个可能对您有用的特定文件:
查看_upload_to_google
函数,了解如何处理此问题。
最后,我最喜欢的作家之一Miguel Grinberg在Celery和Flask上写了一篇很棒的文章,并使用进度条来跟踪你的进度:
http://blog.miguelgrinberg.com/post/using-celery-with-flask
请注意,该示例使用JavaScript每2秒检查一次给定的Celery任务。如果你不期望大量的流量,你当然可以逃脱,但如果容量增长,我建议你看看网络插座。
希望这能让你进入一个良好的起点。祝你好运!
答案 1 :(得分:3)
看来你是解决问题的方法之一
我们需要一个后台工作人员来处理大量数据/文件。如果需要很好的处理时间。 在处理后台任务时,我们没有控制权,所以我们需要DB帮助来跟踪工作状态
按照步骤完成任务,
第1步:在主要路线中执行主要步骤,例如阅读请求(例如:.csv文件)并进行验证,
第2步:创建查找表以跟踪作业状态 此表是占位符,用于跟踪您的后台工作状态
第3步: redis enque:通过redis enque调用处理助手函数并传递所有必需的args,根据需要设置超时值
第4步:进行处理并更新状态记录成功/失败
第5步:创建另一条路线以返回该作业的当前状态,对此路线进行连续的AJAX调用,直到状态变为已完成
通过下面的示例获取更多详细信息假设您已经注意了所有redis设置(例如安装,worke.py,建立redis连接等) #ref
Modles.py (我使用的是Mongo DB)
class TempCsvLookup(Base, Document):
id = SequenceField(unique=True)
job_id = StringField()
file_url = StringField()
status = StringField()
created_at = DateTimeField(default=dt.utcnow(), required=True)
finished_at = DateTimeField(default=(dt.utcnow() + datetime.timedelta(hours=24)))
<强> views.py 强>
@route('/upload_csv_file', methods=['POST'])
@require_login
def upload_csv_file():
#step 1
csv_file = request.form.get('file')
'''
do validations
'''
#Step 2: create a initial DB record
look_up = TempCsvLookup(
status = "Queued"
).save()
#step_3 : calling backgroud task using redis
job = redis_queue.enqueue(
process_csv_file,
args = (
look_up, csv_file, other_args
),
timeout = 1200
)
job.get_id()
look_up.update(
set__job = job.get_id(),
)
return jsonfy(job_id = str(job.get_id()))
def process_csv_file(look_up, csv_file, other_args):
try:
#step 4 process csv file
look_up.update(
set__status = "Processing",
)
"""
1.do all processing with input csv file
2.create new csv file
"""
look_up.update(
set__status = "Completed",
set__file_url = new_file_path,
set__finished_at = dt.utcnow()
)
except Exception as e:
look_up.update(
set__status = "Failed",
set__finished_at = dt.utcnow()
)
@route('/csv_file_lookup/<string:lookup_job_id>', methods=['GET'])
@require_login
def csv_file_lookup(lookup_job_id):
#step5
report = TempCsvLookup.objects(job_id=lookup_job_id).first()
resp = {
'status': report.status,
'file_url': report.file_url
}
return response.success(data=resp)
希望它可以帮助你