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
I had the same problem
The problem is in channels_redis
Using RedisPubSubChannelLayer solves this problem.
However, be careful ahead RedisPubSubChannelLayer is in beta
}
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.