복붙노트

[REDIS] 어떻게 장고 - 셀러리 3 작업에서 채널 2.X 그룹 메시지를 보낼 수 있습니까?

REDIS

어떻게 장고 - 셀러리 3 작업에서 채널 2.X 그룹 메시지를 보낼 수 있습니까?

나는 채널 메시지를 전송하는 연기해야합니다. 여기 내 코드는 다음과 같습니다

# consumers.py
class ChatConsumer(WebsocketConsumer):
    def chat_message(self, event):
        self.send(text_data=json.dumps(event['message']))

    def connect(self):
        self.channel_layer.group_add(self.room_name, self.channel_name)
        self.accept()

    def receive(self, text_data=None, bytes_data=None):
        send_message_task.apply_async(
            args=(
                self.room_name,
                {'type': 'chat_message',
                 'message': 'the message'}
            ),
            countdown=10
        )

# tasks.py
@shared_task
def send_message_task(room_name, message):
    layer = get_channel_layer()
    layer.group_send(room_name, message)

작업이 실행되고 난 오류를 볼 수 있지만, 메시지가 전송되지 않습니다. 내가 소비자 클래스 메소드로 보낼 경우에만 작동합니다.

또한 AsyncWebsocketConsumer을 사용하고 AsyncToSync (layer.group_send)로 전송했습니다. 그것으로 오류 "당신은 비동기 이벤트 루프와 같은 스레드에서 AsyncToSync을 사용할 수 없습니다 -. 단지 직접 비동기 기능을 기다리고 있습니다"

그럼 난 비동기로 send_message_task을 선언하고 await를 사용하여 시도. 아무것도 (오류없이) 다시 발생하고 작업이 전혀 실행되고 있는지 확실하지 않습니다.

다음 버전은 다음과 같습니다

Django==1.11.13
redis==2.10.5
django-celery==3.2.2
channels==2.1.2
channels_redis==2.2.1

설정 :

REDIS_HOST = os.getenv('REDIS_HOST', '127.0.0.1')
BROKER_URL = 'redis://{}:6379/0'.format(REDIS_HOST)
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": ['redis://{}:6379/1'.format(REDIS_HOST)],
        },
    },
}

어떤 아이디어?

UPD : 그냥은 레디 스 채널 층이 입수해온되지만 그것의 group_send 메소드가 호출되지 않고 바로 건너 뛸 것을 알아 냈다.

UPD 2 : 콘솔 작품에서 AsyncToSync (layer.group_send)를 사용하여 전송. apply_async도 작동하지 않고 작업을 호출. 다만 직접 비동기 기능을 기다리고 있습니다 -하지만 apply_async로 실행하면 오류가 당신은 비동기 이벤트 루프와 같은 스레드에서 AsyncToSync을 사용할 수 없습니다됩니다. 비동기로 작업을 정의하고 await를 사용하는 것은 물론 모든 것을 나누기.

해결법

  1. ==============================

    1.어쩌면이 시작 질문하지만,이 힘의 도움에 직접 대답은하지 않습니다. 당신이 예외가 발생하면 "당신은 비동기 이벤트 루프와 같은 스레드에서 AsyncToSync을 사용할 수 없습니다 - 그냥 직접 비동기 기능을 기다리고 있습니다"그때는 아마이 몇 가지 있습니다 :

    어쩌면이 시작 질문하지만,이 힘의 도움에 직접 대답은하지 않습니다. 당신이 예외가 발생하면 "당신은 비동기 이벤트 루프와 같은 스레드에서 AsyncToSync을 사용할 수 없습니다 - 그냥 직접 비동기 기능을 기다리고 있습니다"그때는 아마이 몇 가지 있습니다 :

    AsyncToSync는 외부 이벤트 루프를 감지하고 방해하지 않도록 결정을 내리는 것으로 보인다.

    해결 방법은 직접 외부 이벤트 루프에서 비동기 호출을 포함하는 것입니다. 예제 코드 아래, 그러나 가장 귀하의 상황을 확인하는 것입니다 그 외부 루프가 실행되는 ...

    loop = asyncio.get_event_loop()
    loop.create_task(layer.group_send(room_name, {'type': 'chat_message', 'message': message}))
    
  2. ==============================

    2.모든 채널 층 방법은 비동기이기 때문에 채널 레이어를 사용하면 연결에 async_to_sync () 래퍼가 필요합니다.

    모든 채널 층 방법은 비동기이기 때문에 채널 레이어를 사용하면 연결에 async_to_sync () 래퍼가 필요합니다.

    def connect(self):
        async_to_sync(self.channel_layer.group_add(
            self.room_name, self.channel_name)
        self.accept()
    

    당신의 셀러리 작업에서 메시지를 보내와 같은 거래.

    @shared_task
    def send_message_task(room_name, message):
        channel_layer = get_channel_layer()
    
        async_to_sync(channel_layer.group_send)(
            room_name,
            {'type': 'chat_message', 'message': message}
        )
    

    또한 당신은 다음과 같이) (수신하여 소비자의에서 셀러리 작업을 호출 할 수 있습니다 :

    send_message_task.delay(self.room_name, 'your message here')
    

    이 스레드에 설명 된대로 새 버전으로 채널과 다프네를 업그레이드하는 데 필요한 AsyncToSync 오류에 대해서.

  3. ==============================

    3.나는 못생긴 비효율적 인 의사 결정을 찾았지만, 그것을 작동합니다 :

    나는 못생긴 비효율적 인 의사 결정을 찾았지만, 그것을 작동합니다 :

    @shared_task
    def send_message_task(room_name, message):
        def sender(room_name, message):
            channel_layer = get_channel_layer()
    
            AsyncToSync(channel_layer.group_send)(
                room_name,
                {'type': 'chat_message', 'message': message}
            )
    
        thread = threading.Thread(target=sender, args=(room_name, message,))
        thread.start()
        thread.join()
    

    누군가가 그것을 개선 할 수 있다면, 나는 감사합니다.

  4. ==============================

    4.코드에서 문제는 당신이 당신의 타입 chat_message에 밑줄을 사용한다는 것입니다. 난 당신이 문서에 그것을 놓친 생각 :

    코드에서 문제는 당신이 당신의 타입 chat_message에 밑줄을 사용한다는 것입니다. 난 당신이 문서에 그것을 놓친 생각 :

    귀하의 경우 그래서, 유형 chat.message 될 것입니다

    {
        'type': 'chat.message',
        'message': 'the message'
    }
    
  5. from https://stackoverflow.com/questions/51024893/how-do-i-send-channels-2-x-group-message-from-django-celery-3-task by cc-by-sa and MIT license