Benachrichtigungen fixen mit Redis

This commit is contained in:
Juhn-Vitus Saß
2025-04-22 12:21:47 +02:00
parent 881bc3d6c1
commit 2dc9a077ee
3 changed files with 40 additions and 8 deletions

View File

@@ -61,6 +61,13 @@ Für die Entwicklung mit WebSocket-Unterstützung verwenden wir Daphne:
daphne -b 127.0.0.1 -p 8000 core.asgi:application daphne -b 127.0.0.1 -p 8000 core.asgi:application
``` ```
3. Starte den REDIS Server
```sh
redis-server
```
> **Hinweis:** Der Redis Server muss, wenn er nicht auf dem selben Gerät unter Standardeinstellungen läuft, in der Datei play/consumers/lobby.py und core/settings.py entsprechend umkonfiguriert werden!
Alternativ kannst du den Django-Entwicklungsserver verwenden, wenn du keine WebSocket-Funktionalität benötigst: Alternativ kannst du den Django-Entwicklungsserver verwenden, wenn du keine WebSocket-Funktionalität benötigst:
```sh ```sh
python3 core/manage.py runserver python3 core/manage.py runserver
@@ -91,6 +98,12 @@ Für den Produktivbetrieb verwenden wir Daphne als ASGI-Server, der sowohl HTTP
``` ```
- Dann `0 0 * * * /path/to/venv/bin/python /path/to/your_project/manage.py cleanup_games` einfügen, damit um Mitternacht alle Spiele gelöscht werden - Dann `0 0 * * * /path/to/venv/bin/python /path/to/your_project/manage.py cleanup_games` einfügen, damit um Mitternacht alle Spiele gelöscht werden
5. Starte den REDIS Server
```sh
redis-server
```
> **Hinweis:** Der Redis Server muss, wenn er nicht auf dem selben Gerät unter Standardeinstellungen läuft, in der Datei play/consumers/lobby.py und core/settings.py entsprechend umkonfiguriert werden!
Damit ist das Projekt erfolgreich eingerichtet und der Server kann gestartet werden! Damit ist das Projekt erfolgreich eingerichtet und der Server kann gestartet werden!
## Superuser erstellen ## Superuser erstellen

View File

@@ -79,12 +79,16 @@ WSGI_APPLICATION = 'core.wsgi.application'
ASGI_APPLICATION = 'core.asgi.application' ASGI_APPLICATION = 'core.asgi.application'
CHANNEL_LAYERS = { CHANNEL_LAYERS = {
'default': { "default": {
'BACKEND': 'channels.layers.InMemoryChannelLayer' "BACKEND": "channels_redis.core.RedisChannelLayer",
} "CONFIG": {
"hosts": [("127.0.0.1", 6379)],
},
},
} }
# Database # Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases # https://docs.djangoproject.com/en/5.1/ref/settings/#databases

View File

@@ -3,6 +3,7 @@ import json
import asyncio import asyncio
from ..models import QuizGame, QuizGameParticipant from ..models import QuizGame, QuizGameParticipant
from channels.db import database_sync_to_async from channels.db import database_sync_to_async
import redis
# Dictionary to track inactive check tasks and active connections per game # Dictionary to track inactive check tasks and active connections per game
game_check_tasks = {} game_check_tasks = {}
@@ -10,6 +11,8 @@ game_connections = {}
class LobbyConsumer(AsyncWebsocketConsumer): class LobbyConsumer(AsyncWebsocketConsumer):
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
async def connect(self): async def connect(self):
self.join_code = self.scope['url_route']['kwargs']['join_code'] self.join_code = self.scope['url_route']['kwargs']['join_code']
self.room_group_name = f'lobby_{self.join_code}' self.room_group_name = f'lobby_{self.join_code}'
@@ -142,12 +145,21 @@ class LobbyConsumer(AsyncWebsocketConsumer):
))() ))()
# Send join notification for new participants # Zustand laden
try: try:
prev_names = set(p['display_name'] for p in self.last_participants) if hasattr(self, 'last_participants') else set() r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
# Alte Teilnehmer aus Redis holen
data = r.get(f"last_participants_{self.room_group_name}")
prev_names = set(json.loads(data)) if data else set()
# Aktuelle Teilnehmer aus dem Argument extrahieren
current_names = set(p['display_name'] for p in participants) current_names = set(p['display_name'] for p in participants)
# Neue Teilnehmer bestimmen
new_participants = current_names - prev_names new_participants = current_names - prev_names
# Benachrichtigung für neue Teilnehmer versenden
for name in new_participants: for name in new_participants:
await self.channel_layer.group_send( await self.channel_layer.group_send(
self.room_group_name, self.room_group_name,
@@ -156,9 +168,12 @@ class LobbyConsumer(AsyncWebsocketConsumer):
'player_name': name 'player_name': name
} }
) )
# Teilnehmerliste in Redis aktualisieren
r.set(f"last_participants_{self.room_group_name}", json.dumps(list(current_names)))
except Exception as e: except Exception as e:
print(f'Error sending join notifications: {e}') print(f"Error in send_join_notifications: {e}")
self.last_participants = participants self.last_participants = participants
return participants return participants
except QuizGame.DoesNotExist: except QuizGame.DoesNotExist: