Celery:检查任务是否完成以向

时间:2016-01-14 11:31:44

标签: python-2.7 flask celery

我是芹菜和整个蟒蛇新手的新手。在研究期间,我一定是偶然发现了正确的解决方案,但我似乎并不理解我需要做些什么似乎是一个简单的案例场景。 我跟着following guide了解烧瓶+芹菜。

我的理解:

在第一个任务完成后,似乎有一些显而易见的事情我不知道如何触发任务。我尝试使用回调,使用循环,甚至尝试使用芹菜花和芹菜击败意识到这与我正在做的事情没有任何关系...

目标:

填写表单后,我想发送一封带有附件的电子邮件(任务结果)或者发送失败的电子邮件。不必怀疑我的用户在应用程序上做了什么(没有HTTP请求)

我的代码:

class ClassWithTheTask:
    def __init__(self, filename, proxies):
        # do stuff until a variable results is created
        self.results = 'this contains my result'

@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
def index():
    form = MyForm()

    if form.validate_on_submit():
        # ...
        # the task
        my_task = task1.delay(file_path, proxies)
        return redirect(url_for('taskstatus', task_id=my_task.id, filename=filename, email=form.email.data))

    return render_template('index.html',
                           form=form)

@celery.task(bind=True)
def task1(self, filepath, proxies):
    task = ClassWithTheTask(filepath, proxies)
    return results

@celery.task
def send_async_email(msg):
    """Background task to send an email with Flask-Mail."""
    with app.app_context():
        mail.send(msg)

@app.route('/status/<task_id>/<filename>/<email>')
def taskstatus(task_id, filename, email):
    task = task1.AsyncResult(task_id)

    if task.state == 'PENDING':
        # job did not start yet
        response = {
            'state': task.state,
            'status': 'Pending...'
        }
    elif task.state != 'FAILURE':
        response = {
            'state': task.state,
            'status': task.info.get('status', '')
        }
        if 'results' in task.info:
            response['results'] = task.info['results']
            response['untranslated'] = task.info['untranslated']

        msg = Message('Task Complete for %s !' % filename,
                      recipients=[email])

        msg.body = 'blabla'
        with app.open_resource(response['results']) as fp:
            msg.attach(response['results'], "text/csv", fp.read())
        with app.open_resource(response['untranslated']) as fp:
            msg.attach(response['untranslated'], "text/csv", fp.read())

        # the big problem here is that it will send the email only if the user refreshes the page and get the 'SUCCESS' status.

        send_async_email.delay(msg)
        flash('task finished. sent an email.')
        return redirect(url_for('index'))
    else:
        # something went wrong in the background job
        response = {
            'state': task.state,
            'status': str(task.info),  # this is the exception raised
        }
    return jsonify(response)

2 个答案:

答案 0 :(得分:1)

我没有获得状态检查方法的目标。无论如何,你所描述的都可以这样完成。

if form.validate_on_submit():
        # ...
        # the task
        my_task = (
                    task1.s(file_path, proxies).set(link_error=send_error_email.s(filename, error))
                    | send_async_email.s()
                  ).delay()
        return redirect(url_for('taskstatus', task_id=my_task.id, filename=filename, email=form.email.data))

然后您的错误任务将如下所示。正常的任务可以保持原样。

@celery.task
def send_error_email(task_id, filename, email):
    task = AsyncResult(task_id)
    .....

这里发生的是您正在使用链条。您告诉Celery运行task1,如果成功完成,则运行send_async_email,如果运行send_error_email失败。这应该可行,但您可能需要调整参数,将其视为伪代码。

答案 1 :(得分:0)

这似乎不对:

def task1(self, filepath, proxies):
    task = ClassWithTheTask(filepath, proxies)
    return results

代码中前面的行my_task = task1.delay(file_path, proxies)表示您要返回task,但返回的results未在任何地方定义。 (ClassWithTheTask也未定义)。这段代码会崩溃,你的任务永远不会执行。