Django Channels:使用线程时事件循环正在关闭

Nik*_*las 8 django multithreading websocket django-channels

我想显示倒计时,然后开始游戏循环。代码正在执行并且消息已发送,但我总是收到运行时错误。我对我可以应用的修复或可能更好的解决方案感兴趣。我也在考虑将事物分成两个消费者,但我不知道这将如何解决这个问题。提前致谢。

此错误消息多次弹出。

Task exception was never retrieved
future: <Task finished name='Task-60' coro=<Connection.disconnect() done, defined at D:\Programming\Fullstack\geogame\geogame_backend\env\lib\site-packages\redis\asyncio\connection.py:819> exception=RuntimeError('Event loop is closed')>
Traceback (most recent call last):
  File "D:\Programming\Fullstack\geogame\geogame_backend\env\lib\site-packages\redis\asyncio\connection.py", line 828, in disconnect
    self._writer.close()  # type: ignore[union-attr]
  File "C:\Program Files\Python310\lib\asyncio\streams.py", line 337, in close
    return self._transport.close()
  File "C:\Program Files\Python310\lib\asyncio\selector_events.py", line 698, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "C:\Program Files\Python310\lib\asyncio\base_events.py", line 753, in call_soon
    self._check_closed()
  File "C:\Program Files\Python310\lib\asyncio\base_events.py", line 515, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Run Code Online (Sandbox Code Playgroud)

这是我的消费者

class LobbyConsumer(WebsocketConsumer):

    def __init__(self, *args, **kwargs):
        super().__init__(args, kwargs)
        self.players = None
        self.game_finished = None
        self.host = None
        self.user = None

        self.lobby_code = None
        self.lobby_group_code = None
        self.lobby = None

    def connect(self):
        self.lobby_code = self.scope['url_route']['kwargs']['lobby_code']

        if Lobby.objects.filter(code=self.lobby_code).exists():
            self.lobby = Lobby.objects.get(code=self.lobby_code)
        else:
            print("DOESNT EXIST")
            self.accept()
            self.send(json.dumps({"type": "error", "message": "no_match"}))
            self.close()
            return


        self.lobby_group_code = f"lobby_{self.lobby_code}"

        self.host = Lobby.objects.select_related('host').get(code=self.lobby_code).host

        self.user = self.scope['user']

        if self.user.is_authenticated:
            self.accept()
            print(True)
        else:
            self.close(code=4004)
        self.lobby.users.add(self.user)
        self.lobby.save()

        players_queryset = self.lobby.users.all()


        self.players = []

        for player in players_queryset:
            self.players.append({
                "username": player.username,
                "email": player.email
            })

        async_to_sync(self.channel_layer.group_add)(
            self.lobby_group_code,
            self.channel_name,
        )

        async_to_sync(self.channel_layer.group_send)(
            self.lobby_group_code,
            {
                'type': 'status',
                'message': "Welcome",
                'has_started': self.lobby.has_started,
                'host': self.host.username,
                'players': self.players,
                'lobby_code': self.lobby_code,
                'max_players': self.lobby.max_players,
            }
        )

    def start_game(self):
        countdown = 4
        for i in range(countdown):
            async_to_sync(self.channel_layer.group_send)(
                self.lobby_group_code,
                {
                    'type': 'status',
                    'has_started': self.lobby.has_started,
                    'host': self.host.username,
                    'players': self.players,
                    'lobby_code': self.lobby_code,
                    'countdown': countdown - 1
                }
            )


            sleep(1)

            countdown -= 1



    def receive(self, text_data=None, bytes_data=None):
        command = ""
        text_data_json = json.loads(text_data)
        print(text_data_json)

        if "command" in text_data_json:
            command = text_data_json['command']

            if command == "start":
                self.lobby.has_started = True
                print("start")

                self.lobby.save()

                async_to_sync(self.channel_layer.group_send)(
                    self.lobby_group_code,
                    {
                        'type': 'status',
                        'message': "Welcome",
                        'has_started': self.lobby.has_started,
                        'host': self.host.username,
                        'players': self.players,
                        'lobby_code': self.lobby_code,
                        'countdown': 3
                    }
                )

                thread = Thread(target=self.start_game, args=())
                thread.start()


    def disconnect(self, close_code):
        print(f"Connection Cancelled")

        async_to_sync(
            self.channel_layer.group_discard(
                self.lobby_group_code,
                self.channel_name,
            ))

        self.close()

    def chat_message(self, event):
        self.send(text_data=json.dumps(event))

    def status(self, event):
        self.send(text_data=json.dumps(event))
Run Code Online (Sandbox Code Playgroud)

kja*_*jaw 3

我有同样的问题

问题出在channels_redis中,使用RedisPubSubChannelLayer解决了这个问题。 但是,请注意 RedisPubSubChannelLayer 处于测试阶段

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.pubsub.RedisPubSubChannelLayer",
        "CONFIG": {
            "hosts": ["redis://***:***@***.com:6379"],
        },
},
Run Code Online (Sandbox Code Playgroud)

}