skip to Main Content

I want to show a countdown and then later start a game loop. The code is getting excuted and the messages are send but i always get a RuntimeError. I would be interested in a fix or a maybe better solution that i can apply. I was also thinking about splitting things into two Consumers but i dont know how this would fix this. Thanks in advance.

This error message is popping up multiple times.

Task exception was never retrieved
future: <Task finished name='Task-60' coro=<Connection.disconnect() done, defined at D:ProgrammingFullstackgeogamegeogame_backendenvlibsite-packagesredisasyncioconnection.py:819> exception=RuntimeError('Event loop is closed')>
Traceback (most recent call last):
  File "D:ProgrammingFullstackgeogamegeogame_backendenvlibsite-packagesredisasyncioconnection.py", line 828, in disconnect
    self._writer.close()  # type: ignore[union-attr]
  File "C:Program FilesPython310libasynciostreams.py", line 337, in close
    return self._transport.close()
  File "C:Program FilesPython310libasyncioselector_events.py", line 698, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "C:Program FilesPython310libasynciobase_events.py", line 753, in call_soon
    self._check_closed()
  File "C:Program FilesPython310libasynciobase_events.py", line 515, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

This is my consumer

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))

2

Answers


  1. I had the same problem

    The problem is in channels_redis
    Using RedisPubSubChannelLayer solves this problem.
    However, be careful ahead RedisPubSubChannelLayer is in beta

    CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels_redis.pubsub.RedisPubSubChannelLayer",
            "CONFIG": {
                "hosts": ["redis://***:***@***.com:6379"],
            },
    },
    

    }

    Login or Signup to reply.
  2. I had a problem with event loop closing after an arbitrary amount of time. The issue was in the channels-redis module. It got updated accidentally. After checking every module’s version, I rolled it back and it worked well again.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search