Flask-SocketIO редис подписывайся - PullRequest
0 голосов
/ 01 октября 2018

Я использую https://github.com/miguelgrinberg/Flask-SocketIO для реализации сервера WebSocket.

Мне нужно получить сообщение от другого процесса (только подписаться) и отправить его клиентам в определенной комнате.

Но, когда я пытаюсь отправить сообщение, я получаю эту ошибку:

Не удалось отправить сообщение в домашнюю комнату: Работа вне контекста запроса.

Вот мой код:

from flask import Flask, request
from flask_socketio import SocketIO, join_room, leave_room, send, rooms
import json
import eventlet
import logging
import redis
import threading

FORMAT = '%(asctime)-15s - %(message)s'
logging.basicConfig(format=FORMAT)
log = logging.getLogger(__name__)

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode='eventlet')

.
.
.

def _send_task_message():
    try:
        send(json.dumps({"type":"UPDATE_TASK"}), room='home')
    except Exception as e:
        log.error('Could not send message to home room: %s' % str(e)) 

class Listener(threading.Thread):
    def __init__(self, r, channels):
        threading.Thread.__init__(self)
        self.daemon = True
        self.redis = r
        self.pubsub = self.redis.pubsub()
        self.pubsub.psubscribe(channels)

    def work(self, item):
        if isinstance(item['data'], bytes):
            try:
                msg = item['data'].decode('utf-8')
                decode_msg = json.loads(msg)                
                if decode_msg['type'] == 'UPDATE_TASK':
                    _send_task_message()
            except ValueError as e:
                log.error("Error decoding msg to microservice: %s", str(e))

    def run(self):
        for item in self.pubsub.listen():
            self.work(item)


if __name__ == '__main__':

    r = redis.Redis()
    client = Listener(r, ['/bobguarana/socketio'])
    client.start()

    socketio.run(debug=True, app=app, port=8080)

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

Я решил передать приложение в качестве аргумента классу и использовать его контекст, как предлагается в описании ошибки, но пространство имен тоже необходимо:

class Listener(threading.Thread):
    def __init__(self, r, channels, app):
    threading.Thread.__init__(self)
    self.daemon = True
    self.redis = r
    self.pubsub = self.redis.pubsub()
    self.pubsub.psubscribe(channels)
    self.app = app

    def work(self, item):
        with app.app_context():
            if isinstance(item['data'], bytes):
                try:
                    msg = item['data'].decode('utf-8')
                    decode_msg = json.loads(msg)                
                    if decode_msg['type'] == 'UPDATE_TASK':
                        send(json.dumps({"type":"UPDATE_TASK"}), room='home', namespace='/')
                    #_send_task_message()
                except ValueError as e:
                    log.error("Error decoding msg to microservice: %s", str(e))

    def run(self):
        for item in self.pubsub.listen():
            self.work(item)

if __name__ == '__main__':

    r = redis.Redis()
    client = Listener(r, ['/bobguarana/socketio'], app)
    client.start()

    socketio.run(debug=True, app=app, port=8080)
0 голосов
/ 02 октября 2018

Если вы посмотрите на исходный код метода flask_socketio.send , вы увидите, что если пространство имен пропущено, flask_socketio попытается получить его из текущего запроса.Но когда вы получите сообщение от вашего Redis, не будет никакого текущего запроса для получения пространства имен.Таким образом, чтобы отправлять сообщения socketio без текущего запроса (который в Flask называется request context), вы должны указать пространство имен (по умолчанию '/', IIRC):

send(json.dumps({"type":"UPDATE_TASK"}), room='home', namespace='/')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...