fix(music): add Lavalink health-check with auto-reconnect
- Add 30s scheduled health-check that detects unavailable nodes - Remove and re-add node when it becomes unavailable (fixes WS disconnect) - Log WebSocketClosedEvent for debugging connection drops
This commit is contained in:
parent
520dccbafe
commit
ad17cff40e
2 changed files with 54 additions and 4 deletions
|
|
@ -9,6 +9,7 @@ import dev.arbjerg.lavalink.client.event.ReadyEvent;
|
||||||
import dev.arbjerg.lavalink.client.event.StatsEvent;
|
import dev.arbjerg.lavalink.client.event.StatsEvent;
|
||||||
import dev.arbjerg.lavalink.client.event.TrackEndEvent;
|
import dev.arbjerg.lavalink.client.event.TrackEndEvent;
|
||||||
import dev.arbjerg.lavalink.client.event.TrackStartEvent;
|
import dev.arbjerg.lavalink.client.event.TrackStartEvent;
|
||||||
|
import dev.arbjerg.lavalink.client.event.WebSocketClosedEvent;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
@ -65,5 +66,18 @@ class LavalinkEventRouter {
|
||||||
manager.getScheduler().onTrackEnd(event.getTrack(), event.getEndReason());
|
manager.getScheduler().onTrackEnd(event.getTrack(), event.getEndReason());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
client
|
||||||
|
.on(WebSocketClosedEvent.class)
|
||||||
|
.subscribe(
|
||||||
|
event ->
|
||||||
|
LoggerDecorator.music(
|
||||||
|
logger,
|
||||||
|
"WebSocket закрыт: code="
|
||||||
|
+ event.getCode()
|
||||||
|
+ ", reason="
|
||||||
|
+ event.getReason()
|
||||||
|
+ ", byRemote="
|
||||||
|
+ event.getByRemote()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ package creator.loki.feature.music.core;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.LongConsumer;
|
import java.util.function.LongConsumer;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
@ -27,6 +30,13 @@ public class LavalinkManager {
|
||||||
private final BotConfig config;
|
private final BotConfig config;
|
||||||
private final QueueRepository queueRepository;
|
private final QueueRepository queueRepository;
|
||||||
private volatile LongConsumer voiceDisconnectHandler;
|
private volatile LongConsumer voiceDisconnectHandler;
|
||||||
|
private final ScheduledExecutorService healthCheck =
|
||||||
|
Executors.newSingleThreadScheduledExecutor(
|
||||||
|
r -> {
|
||||||
|
Thread t = new Thread(r, "lavalink-health-check");
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LavalinkManager(BotConfig config, QueueRepository queueRepository) {
|
public LavalinkManager(BotConfig config, QueueRepository queueRepository) {
|
||||||
|
|
@ -46,6 +56,17 @@ public class LavalinkManager {
|
||||||
|
|
||||||
this.client = new LavalinkClient(Helpers.getUserIdFromToken(botToken));
|
this.client = new LavalinkClient(Helpers.getUserIdFromToken(botToken));
|
||||||
|
|
||||||
|
addNode(lavalinkConfig);
|
||||||
|
|
||||||
|
new LavalinkEventRouter(client, musicManagers).register();
|
||||||
|
|
||||||
|
healthCheck.scheduleWithFixedDelay(this::checkNodeHealth, 30, 30, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
LoggerDecorator.music(
|
||||||
|
logger, "LavalinkManager инициализирован, нода: " + lavalinkConfig.getWsUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addNode(LavalinkConfig lavalinkConfig) {
|
||||||
client.addNode(
|
client.addNode(
|
||||||
new NodeOptions.Builder()
|
new NodeOptions.Builder()
|
||||||
.setName("main")
|
.setName("main")
|
||||||
|
|
@ -53,11 +74,26 @@ public class LavalinkManager {
|
||||||
.setPassword(lavalinkConfig.getPassword())
|
.setPassword(lavalinkConfig.getPassword())
|
||||||
.setHttpTimeout(30000L)
|
.setHttpTimeout(30000L)
|
||||||
.build());
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
new LavalinkEventRouter(client, musicManagers).register();
|
private void checkNodeHealth() {
|
||||||
|
try {
|
||||||
LoggerDecorator.music(
|
var nodes = client.getNodes();
|
||||||
logger, "LavalinkManager инициализирован, нода: " + lavalinkConfig.getWsUri());
|
if (nodes.isEmpty()) {
|
||||||
|
logger.warn("Lavalink: нет нод, пересоздаю");
|
||||||
|
addNode(config.getLavalinkConfig());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var node = nodes.get(0);
|
||||||
|
if (!node.getAvailable()) {
|
||||||
|
logger.warn("Lavalink нода '{}' недоступна, переподключаю", node.getName());
|
||||||
|
client.removeNode(node);
|
||||||
|
addNode(config.getLavalinkConfig());
|
||||||
|
LoggerDecorator.music(logger, "Lavalink нода переподключена");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Ошибка health-check Lavalink", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LavalinkClient getClient() {
|
public LavalinkClient getClient() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue