如何让Celery worker从任务中返回结果

时间:2016-07-08 13:07:24

标签: python flask celery

我有一个烧瓶应用程序,可以调用任务。该任务从数据库中提取数据,绘制折线图并返回在html页面上呈现的html内容。没有Celery,Flask应用程序工作正常并在客户端呈现折线图,但现在我想委托celery通过RabbitMQ代理运行任务,它运行它,因为我可以看到Celery shell中的日志输出,但结果html内容永远不会被发送回烧瓶服务器应用程序。怎么做?

这是http://stackoverflow.com/questions/37839551/how-to-restart-flask-process-by-refreshing-page/38146003#38146003的后续行动。

#server-celery.py

app = Flask(__name__)

@app.route('/',methods=['GET'])
def index():
   return render_template("index.html")

@app.route('/', methods=['GET', 'POST'])
def plotdata():
   form = InputForm(request.form)
   if request.method == 'POST' and form.validate():
       lineChart = task.main.delay(form.startdate.data, form.enddate.data) 
       return render_template('view.html', form=form, result= lineChart)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

任务以Celery worker运行:

#task.py
from celery import Celery

broker = 'amqp://localhost:5672'
app = Celery(__name__, broker=broker)

def queryDatabase(param1, param2):
   #query database, return results
   return data

def plotLineChart(data):
   #plot data as line Chart
   return LineChartHtmlcontent

@app.task
def main(param1,param2):
    data = queryDatabase(param1,param2)
    return plotLineChart(data)

和客户端html页面:

<!--view.html-->

<form method=post action="">
<table>
  {% for field in form %}
    <tr>
    <td>{{ field.label }}</td>
        <td>{{ field }}</td>

    </tr>
  {% endfor %}
</table>
<p><input type=submit value=Submit></form></p>

<p>
{% if result != None %}
<img src="{{ result }}" width="500">
{% endif %}
</p>

1 个答案:

答案 0 :(得分:0)

更好的解决方案就是让使用celery异步运行任务,就像打算使用它一样,并在页面上使用javascript定期轮询芹菜任务以查看状态。

首先,在创建celery任务时,使用bind = True参数。这允许您将self传递给函数。

@app.task(bind=True)
def main(self, param1, param2):
    self.update_state(state='PENDING')
    data = queryDatabase(param1,param2)
    self.update_state(state='COMPLETE')
    return plotLineChart(data)

您可以看到我们现在可以更新任务的状态。您可以修改代码以允许元数据加入update_state方法,例如:self.update_state(state='PROGRESS', meta={'current': 0, 'total': 12})

现在你需要轮询芹菜任务,看看它是如何做的。

@blueprint.route('/status/<task_id>', methods=['GET'])
def taskstatus(task_id=None):
    task = main.AsyncResult(task_id)
    response = {
        'state': task.state,
    }
    return jsonify(response)

当您使用任务ID轮询URL时,这将返回一个json对象。致电lineChart.id

后,您可以使用.delay()获取任务ID

请参阅miguel grinberg的优秀教程:http://blog.miguelgrinberg.com/post/using-celery-with-flask