从 Celery 任务发送事件 - Flask-SocketIO + Celery

时间:2021-05-30 00:43:18

标签: python flask socket.io flask-socketio

我正在尝试将事件从 Celery 任务发送到服务器,以便我可以向客户端发送数据。

enter image description here

  1. 用户提交带有文本的表单
  2. 服务器接收表单提交
  3. 服务器将表单数据发送到 Celery 任务队列
  4. Celery 处理任务
  5. Celery 将处理后的数据发送回服务器
  6. 服务器将数据发送到客户端,并显示在网页上

这是我目前拥有的:

routes.py

@main_bp.route('/', methods=['GET', 'POST'])
def index():
    form = UserTextForm()
    if request.method == 'POST':
        request_data = request.form.to_dict()

        user_text = request_data['user_text']

        run_processing_task.apply_async(args=[user_text])

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

@socketio.on('my_event', namespace='/user_text_task_results')
def user_test_task_results(my_event):
    # Sends data to client
    send(my_event, broadcast=True)
celery_tasks.py

@celery.task(bind=True)
def run_processing_task(self, user_text):
    print('Celery Function kicked off')

    local_socketio = SocketIO(message_queue='redis://localhost:6379/0')

    time.sleep(3)
    user_text_reverse = user_text[::-1]
    local_socketio.emit('my_event', {'data': user_text_reverse}, namespace='/user_text_task_results')

    print('Task Completed')

    return 'Finished'
index.html

<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    <h1>Welcome</h1>
</head>


<form method="POST" action="{{ url_for('main_bp.index') }}" class="col-6">
  {{ form.hidden_tag() }}
    <div class="form-group">
    {{ form.user_text(class="form-control", id="user-text-area") }}
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

<div id="test-app">
</div>

<script>
    $(document).ready(function() {
        var socket = io.connect('http://127.0.0.1:5000');

        socket.on('connect', function() {
            socket.send('User Connected')
        });

        socket.on('message', function(results){
            var reversed_text = results['data']
            $("$test-app").append('<p>'+reversed_text+</p>)
        });
    });
</script>

当我运行上面的时候,任务被处理了,但是我认为服务器没有收到数据local_socketio.emit(...)。我可以看到 Celery 任务成功完成,但我没有看到任何迹象表明数据流向服务器并最终流向客户端。

我尝试安装 gevent 和 gevent-websocket,但随后索引不会为初始 GET 请求事件加载(它只是挂在加载状态)

1 个答案:

答案 0 :(得分:1)

Celery 工作人员通常运行与 Flask 应用程序相同的代码,但它们不作为flask 服务器运行,因此从celery 到flask 的websocket 并不是一件容易的事情。 (我从未见过它完成,但也许有人已经解决了棘手的部分。)

假设您想避免让客户端或应用轮询任务完成,另一种方法是通过向应用发出 HTTP 请求来让工作线程完成信号。即,类似于 POST 到

/tasks/complete/<task_id>

然后是一个应用程序问题已经完成了将 task_id 与特定 websocket 相关联的簿记。

添加:

Celery 有一个 post_run 信号,应该用于相同的目的。几年前我运气不好,但现在觉得我做了一些愚蠢的事情。