Switch game.join and leaderboard handlers (leaderboard.get, leaderboard.request) to NATS Queue Groups, remove room-to-pod assignment logic for simplified load balancing, and add detailed Pod-specific logging.
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m29s
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m29s
This commit is contained in:
@@ -111,8 +111,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
log.Printf("✅ Verbunden mit NATS: %s", natsURL)
|
log.Printf("✅ Verbunden mit NATS: %s", natsURL)
|
||||||
|
|
||||||
// 3. HANDLER: GAME JOIN (broadcast - alle Pods hören, aber nur zuständiger erstellt)
|
// 3. HANDLER: GAME JOIN (Queue Group - nur EIN Pod bekommt den JOIN)
|
||||||
sub, err := ec.Subscribe("game.join", func(req *game.JoinRequest) {
|
sub, err := ec.QueueSubscribe("game.join", "room-handlers", func(req *game.JoinRequest) {
|
||||||
playerID := req.Name
|
playerID := req.Name
|
||||||
if playerID == "" {
|
if playerID == "" {
|
||||||
playerID = "Unknown"
|
playerID = "Unknown"
|
||||||
@@ -123,13 +123,7 @@ func main() {
|
|||||||
roomID = "lobby"
|
roomID = "lobby"
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("📥 JOIN empfangen: Name=%s, RoomID=%s", req.Name, roomID)
|
log.Printf("📥 JOIN empfangen: Name=%s, RoomID=%s (Pod: %s)", req.Name, roomID, serverID)
|
||||||
|
|
||||||
// Prüfe ob dieser Pod für den Raum zuständig ist
|
|
||||||
if !isResponsibleForRoom(roomID) {
|
|
||||||
log.Printf("⏭️ Überspringe JOIN - nicht zuständig für Raum '%s'", roomID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
@@ -137,7 +131,7 @@ func main() {
|
|||||||
// Raum finden oder erstellen
|
// Raum finden oder erstellen
|
||||||
room, exists := rooms[roomID]
|
room, exists := rooms[roomID]
|
||||||
if !exists {
|
if !exists {
|
||||||
log.Printf("🆕 Erstelle neuen Raum: '%s' (zuständiger Pod)", roomID)
|
log.Printf("🆕 Erstelle neuen Raum: '%s' auf Pod %s", roomID, serverID)
|
||||||
room = server.NewRoom(roomID, nc, globalWorld)
|
room = server.NewRoom(roomID, nc, globalWorld)
|
||||||
rooms[roomID] = room
|
rooms[roomID] = room
|
||||||
|
|
||||||
@@ -158,7 +152,7 @@ func main() {
|
|||||||
|
|
||||||
// Session speichern
|
// Session speichern
|
||||||
playerSessions[playerID] = room
|
playerSessions[playerID] = room
|
||||||
log.Printf("➡️ Spieler '%s' ist Raum '%s' beigetreten.", playerID, roomID)
|
log.Printf("✅ Spieler '%s' ist Raum '%s' beigetreten (Pod: %s).", playerID, roomID, serverID)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -229,17 +223,17 @@ func main() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 7. HANDLER: LEADERBOARD REQUEST (alt, für Kompatibilität)
|
// 7. HANDLER: LEADERBOARD REQUEST (alt, für Kompatibilität) - Queue Group
|
||||||
_, _ = ec.Subscribe("leaderboard.get", func(subject, reply string, _ *struct{}) {
|
_, _ = ec.QueueSubscribe("leaderboard.get", "leaderboard-handlers", func(subject, reply string, _ *struct{}) {
|
||||||
top10 := server.GlobalLeaderboard.GetTop10()
|
top10 := server.GlobalLeaderboard.GetTop10()
|
||||||
log.Printf("📊 Leaderboard-Request beantwortet: %d Einträge", len(top10))
|
log.Printf("📊 Leaderboard-Request beantwortet: %d Einträge (Pod: %s)", len(top10), serverID)
|
||||||
ec.Publish(reply, top10)
|
ec.Publish(reply, top10)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 8. HANDLER: LEADERBOARD REQUEST (neu, für WebSocket-Gateway)
|
// 8. HANDLER: LEADERBOARD REQUEST (neu, für WebSocket-Gateway) - Queue Group
|
||||||
_, _ = ec.Subscribe("leaderboard.request", func(req *game.LeaderboardRequest) {
|
_, _ = ec.QueueSubscribe("leaderboard.request", "leaderboard-handlers", func(req *game.LeaderboardRequest) {
|
||||||
top10 := server.GlobalLeaderboard.GetTop10()
|
top10 := server.GlobalLeaderboard.GetTop10()
|
||||||
log.Printf("📊 Leaderboard-Request (Mode=%s): %d Einträge", req.Mode, len(top10))
|
log.Printf("📊 Leaderboard-Request (Mode=%s): %d Einträge (Pod: %s)", req.Mode, len(top10), serverID)
|
||||||
|
|
||||||
// Response an den angegebenen Channel senden
|
// Response an den angegebenen Channel senden
|
||||||
if req.ResponseChannel != "" {
|
if req.ResponseChannel != "" {
|
||||||
@@ -267,40 +261,6 @@ func getEnv(key, defaultValue string) string {
|
|||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// isResponsibleForRoom prüft ob dieser Pod für den Raum zuständig ist
|
|
||||||
func isResponsibleForRoom(roomID string) bool {
|
|
||||||
// Wenn nur 1 Replica läuft, sind wir immer zuständig
|
|
||||||
totalReplicas := getEnv("TOTAL_REPLICAS", "1")
|
|
||||||
if totalReplicas == "1" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(roomID) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash-basierte Zuweisung: RoomID → Pod
|
|
||||||
// Verwende einfachen Hash für bessere Verteilung
|
|
||||||
hash := 0
|
|
||||||
for _, c := range roomID {
|
|
||||||
hash = (hash*31 + int(c)) % 2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bestimme Pod-Nummer aus ServerID
|
|
||||||
podNumber := 0
|
|
||||||
if len(serverID) > 0 {
|
|
||||||
lastChar := serverID[len(serverID)-1]
|
|
||||||
if lastChar >= '0' && lastChar <= '9' {
|
|
||||||
podNumber = int(lastChar - '0')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
responsible := (hash % 2) == (podNumber % 2)
|
|
||||||
log.Printf("🎯 Room '%s' → Hash=%d, Pod=%d (%s) → Responsible=%v", roomID, hash, podNumber, serverID, responsible)
|
|
||||||
|
|
||||||
return responsible
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadServerAssets(w *game.World) {
|
func loadServerAssets(w *game.World) {
|
||||||
assetDir := "./cmd/client/web/assets"
|
assetDir := "./cmd/client/web/assets"
|
||||||
chunkDir := filepath.Join(assetDir, "chunks")
|
chunkDir := filepath.Join(assetDir, "chunks")
|
||||||
|
|||||||
Reference in New Issue
Block a user