8

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:\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

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

2 Answers 2

4

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"],
        },
},

}

Sign up to request clarification or add additional context in comments.

Comments

0

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.

1 Comment

Yes, it will also solve the problem - only previous versions have a security problems

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.