Skip to content

Commit 0c685df

Browse files
authored
Add minimum online checks for a server to be considered online (#236)
1 parent 6e8cf6a commit 0c685df

File tree

14 files changed

+216
-55
lines changed

14 files changed

+216
-55
lines changed

shared/src/main/java/net/pistonmaster/pistonqueue/shared/config/Config.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ public final class Config {
6767
@Comment("It is not recommended to decrease this number (milliseconds)")
6868
private int serverOnlineCheckDelay = 500;
6969

70+
@Comment("How many online checks need to be successful before we consider the server online")
71+
private int minOnlineChecks = 3;
72+
7073
@Comment("Where to send the queue position message and what to send.")
7174
private boolean positionMessageChat = true;
7275
private boolean positionMessageHotBar = false;
@@ -207,6 +210,7 @@ public void copyFrom(Config source) {
207210
registerTab = source.registerTab;
208211
serverIsFullMessage = source.serverIsFullMessage;
209212
serverOnlineCheckDelay = source.serverOnlineCheckDelay;
213+
minOnlineChecks = source.minOnlineChecks;
210214
positionMessageChat = source.positionMessageChat;
211215
positionMessageHotBar = source.positionMessageHotBar;
212216
queuePosition = source.queuePosition;
@@ -278,6 +282,10 @@ public int serverOnlineCheckDelay() {
278282
return serverOnlineCheckDelay;
279283
}
280284

285+
public int minOnlineChecks() {
286+
return minOnlineChecks;
287+
}
288+
281289
public boolean positionMessageChat() {
282290
return positionMessageChat;
283291
}
@@ -527,6 +535,10 @@ public void setServerIsFullMessage(String message) {
527535
this.serverIsFullMessage = message;
528536
}
529537

538+
public void setMinOnlineChecks(int minOnlineChecks) {
539+
this.minOnlineChecks = minOnlineChecks;
540+
}
541+
530542
public void setServerDownKickMessage(String message) {
531543
this.serverDownKickMessage = message;
532544
}

shared/src/main/java/net/pistonmaster/pistonqueue/shared/plugin/PistonQueuePlugin.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ default void scheduleTasks(QueueListenerShared queueListener) {
8585
final QueueGroup defaultGroup = resolvedDefaultGroup;
8686
// Sends the position message and updates tab on an interval in chat
8787
schedule(() -> {
88-
boolean targetsOnline = defaultGroup.targetServers().stream().anyMatch(queueListener.getOnlineServers()::contains);
88+
boolean targetsOnline = defaultGroup.targetServers().stream().anyMatch(queueListener.getServerStatusManager().getOnlineServers()::contains);
8989
if (targetsOnline) {
9090
for (QueueType type : config.getAllQueueTypes()) {
9191
if (config.positionMessageChat()) {
@@ -126,25 +126,24 @@ default void scheduleTasks(QueueListenerShared queueListener) {
126126
List<String> servers = new ArrayList<>(config.kickWhenDownServers());
127127
CountDownLatch latch = new CountDownLatch(servers.size());
128128
for (String server : servers) {
129-
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
129+
CompletableFuture.runAsync(() -> {
130130
try {
131131
Optional<ServerInfoWrapper> serverInfoWrapper = getServer(server);
132132

133133
if (serverInfoWrapper.isPresent()) {
134134
if (serverInfoWrapper.get().isOnline()) {
135-
queueListener.getOnlineServers().add(server);
135+
queueListener.getServerStatusManager().online(server);
136136
} else {
137137
warning("Server %s is down!!!".formatted(server));
138-
queueListener.getOnlineServers().remove(server);
138+
queueListener.getServerStatusManager().offline(server);
139139
}
140140
} else {
141141
warning("Server \"%s\" not set up!!! Check out: https://github.com/AlexProgrammerDE/PistonQueue/wiki/FAQ#server-not-set-up-error".formatted(server));
142142
}
143143
} finally {
144144
latch.countDown();
145145
}
146-
});
147-
future.exceptionally(ex -> {
146+
}).exceptionally(ex -> {
148147
error("Failed to check status of server " + server + ": " + ex.getMessage());
149148
return null;
150149
});

shared/src/main/java/net/pistonmaster/pistonqueue/shared/queue/QueueListenerShared.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
public abstract class QueueListenerShared {
4848
private final PistonQueuePlugin plugin;
4949
@Getter
50-
private final Set<String> onlineServers = ConcurrentHashMap.newKeySet();
50+
private final ServerStatusManager serverStatusManager;
5151
private final QueueEnvironment queueEnvironment;
5252
private final QueuePlacementCoordinator queuePlacementCoordinator;
5353
private final QueueMoveProcessor queueMoveProcessor;
@@ -57,8 +57,9 @@ public abstract class QueueListenerShared {
5757

5858
protected QueueListenerShared(PistonQueuePlugin plugin) {
5959
this.plugin = plugin;
60-
this.queueEnvironment = new QueueEnvironment(plugin, this::currentConfig, onlineServers);
6160
Config config = currentConfig();
61+
this.serverStatusManager = new ServerStatusManager(this::currentConfig);
62+
this.queueEnvironment = new QueueEnvironment(plugin, this::currentConfig, serverStatusManager::getOnlineServers);
6263
this.usernameValidator = new UsernameValidator(config);
6364
this.shadowBanKickHandler = new ShadowBanKickHandler(config);
6465

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package net.pistonmaster.pistonqueue.shared.queue;
2+
3+
import net.pistonmaster.pistonqueue.shared.config.Config;
4+
5+
import java.util.Map;
6+
import java.util.Set;
7+
import java.util.concurrent.ConcurrentHashMap;
8+
import java.util.function.Supplier;
9+
import java.util.stream.Collectors;
10+
11+
public class ServerStatusManager {
12+
private final Supplier<Config> configSupplier;
13+
14+
private final Map<String, Integer> onlinePingCounts = new ConcurrentHashMap<>();
15+
16+
public ServerStatusManager(Supplier<Config> configSupplier) {
17+
this.configSupplier = configSupplier;
18+
}
19+
20+
public void online(String server) {
21+
onlinePingCounts.merge(server, 1, (oldValue, newValue) -> {
22+
//this prevents overflows, count never goes over the configured amount
23+
final int sum = Integer.sum(oldValue, newValue);
24+
if (sum > configSupplier.get().minOnlineChecks()) {
25+
return oldValue;
26+
}
27+
return sum;
28+
});
29+
}
30+
31+
public void offline(String server) {
32+
onlinePingCounts.remove(server);
33+
}
34+
35+
public Set<String> getOnlineServers() {
36+
return onlinePingCounts.entrySet().stream()
37+
.filter(entry -> entry.getValue() >= configSupplier.get().minOnlineChecks())
38+
.map(Map.Entry::getKey)
39+
.collect(Collectors.toSet());
40+
}
41+
42+
// For testing purposes so we can assert there is no overflow risk
43+
public int getOnlinePingCount(String server) {
44+
return onlinePingCounts.getOrDefault(server, 0);
45+
}
46+
}

shared/src/main/java/net/pistonmaster/pistonqueue/shared/queue/logic/QueueEnvironment.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121

2222
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2323
import net.pistonmaster.pistonqueue.shared.config.Config;
24+
import net.pistonmaster.pistonqueue.shared.plugin.PistonQueuePlugin;
2425
import net.pistonmaster.pistonqueue.shared.queue.QueueGroup;
2526
import net.pistonmaster.pistonqueue.shared.queue.QueueType;
26-
import net.pistonmaster.pistonqueue.shared.plugin.PistonQueuePlugin;
2727

2828
import java.util.List;
2929
import java.util.Objects;
@@ -35,12 +35,12 @@
3535
public final class QueueEnvironment {
3636
private final PistonQueuePlugin plugin;
3737
private final Supplier<Config> configSupplier;
38-
private final Set<String> onlineServers;
38+
private final Supplier<Set<String>> onlineServersSupplier;
3939

40-
public QueueEnvironment(PistonQueuePlugin plugin, Supplier<Config> configSupplier, Set<String> onlineServers) {
40+
public QueueEnvironment(PistonQueuePlugin plugin, Supplier<Config> configSupplier, Supplier<Set<String>> onlineServersSupplier) {
4141
this.plugin = Objects.requireNonNull(plugin, "plugin");
4242
this.configSupplier = Objects.requireNonNull(configSupplier, "configSupplier");
43-
this.onlineServers = Objects.requireNonNull(onlineServers, "onlineServers");
43+
this.onlineServersSupplier = Objects.requireNonNull(onlineServersSupplier, "onlineServersSupplier");
4444
}
4545

4646
@SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Plugin API is immutable for consumers")
@@ -52,9 +52,8 @@ public Config config() {
5252
return configSupplier.get();
5353
}
5454

55-
@SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Caller needs live view for synchronization")
5655
public Set<String> onlineServers() {
57-
return onlineServers;
56+
return onlineServersSupplier.get();
5857
}
5958

6059
public QueueGroup defaultGroup() {
@@ -94,14 +93,14 @@ public String defaultTarget(QueueGroup group) {
9493
}
9594

9695
public boolean isGroupTargetOnline(QueueGroup group) {
97-
return group.targetServers().stream().anyMatch(onlineServers::contains);
96+
return group.targetServers().stream().anyMatch(onlineServers()::contains);
9897
}
9998

10099
/// Checks if at least one queue server in the group is online.
101100
///
102101
/// @param group the queue group to check
103102
/// @return true if at least one queue server is online
104103
public boolean isGroupQueueServerOnline(QueueGroup group) {
105-
return group.queueServers().stream().anyMatch(onlineServers::contains);
104+
return group.queueServers().stream().anyMatch(onlineServers()::contains);
106105
}
107106
}

shared/src/test/java/net/pistonmaster/pistonqueue/shared/queue/logic/KickEventHandlerTest.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void redirectsToQueueWhenKickedFromDownTargetServer() {
4141
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
4242
QueueGroup group = QueueTestUtils.defaultGroup(config);
4343
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
44-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
44+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
4545
QueueServerSelector selector = new QueueServerSelector(environment);
4646
KickEventHandler handler = new KickEventHandler(config, environment, selector);
4747

@@ -65,7 +65,7 @@ void doesNotRedirectWhenQueueRedirectionDisabled() {
6565

6666
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
6767
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
68-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
68+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
6969
QueueServerSelector selector = new QueueServerSelector(environment);
7070
KickEventHandler handler = new KickEventHandler(config, environment, selector);
7171

@@ -87,7 +87,7 @@ void doesNotRedirectWhenKickedFromNonTargetServer() {
8787

8888
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
8989
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
90-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
90+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
9191
QueueServerSelector selector = new QueueServerSelector(environment);
9292
KickEventHandler handler = new KickEventHandler(config, environment, selector);
9393

@@ -109,7 +109,7 @@ void doesNotRedirectWhenKickReasonDoesNotMatch() {
109109

110110
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
111111
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
112-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
112+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
113113
QueueServerSelector selector = new QueueServerSelector(environment);
114114
KickEventHandler handler = new KickEventHandler(config, environment, selector);
115115

@@ -130,7 +130,7 @@ void setsCustomKickMessageWhenEnabledAndWillDisconnect() {
130130

131131
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
132132
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
133-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
133+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
134134
QueueServerSelector selector = new QueueServerSelector(environment);
135135
KickEventHandler handler = new KickEventHandler(config, environment, selector);
136136

@@ -151,7 +151,7 @@ void doesNotSetKickMessageWhenDisabled() {
151151

152152
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
153153
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
154-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
154+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
155155
QueueServerSelector selector = new QueueServerSelector(environment);
156156
KickEventHandler handler = new KickEventHandler(config, environment, selector);
157157

@@ -172,7 +172,7 @@ void doesNotSetKickMessageWhenNotDisconnecting() {
172172

173173
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
174174
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
175-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
175+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
176176
QueueServerSelector selector = new QueueServerSelector(environment);
177177
KickEventHandler handler = new KickEventHandler(config, environment, selector);
178178

@@ -194,7 +194,7 @@ void handlesKickWithoutReason() {
194194

195195
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
196196
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
197-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
197+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
198198
QueueServerSelector selector = new QueueServerSelector(environment);
199199
KickEventHandler handler = new KickEventHandler(config, environment, selector);
200200

@@ -217,7 +217,7 @@ void caseInsensitiveKickReasonMatching() {
217217
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
218218
QueueGroup group = QueueTestUtils.defaultGroup(config);
219219
Set<String> onlineServers = QueueTestUtils.onlineServers("queue", "target");
220-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
220+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
221221
QueueServerSelector selector = new QueueServerSelector(environment);
222222
KickEventHandler handler = new KickEventHandler(config, environment, selector);
223223

shared/src/test/java/net/pistonmaster/pistonqueue/shared/queue/logic/QueueCleanerTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void removesStaleEntriesWhenPlayerDisconnected() {
3737
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
3838
QueueGroup group = QueueTestUtils.defaultGroup(config);
3939
Set<String> onlineServers = QueueTestUtils.onlineServers(group.queueServers().toArray(String[]::new));
40-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
40+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
4141
QueueCleaner cleaner = new QueueCleaner(environment);
4242

4343
QueueType type = QueueTestUtils.defaultQueueType(config);
@@ -56,7 +56,7 @@ void keepsActiveQueueEntries() {
5656
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
5757
QueueGroup group = QueueTestUtils.defaultGroup(config);
5858
Set<String> onlineServers = QueueTestUtils.onlineServers(group.queueServers().toArray(String[]::new));
59-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
59+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
6060
QueueCleaner cleaner = new QueueCleaner(environment);
6161

6262
QueueType type = QueueTestUtils.defaultQueueType(config);
@@ -76,7 +76,7 @@ void handlesEmptyQueue() {
7676
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
7777
QueueGroup group = QueueTestUtils.defaultGroup(config);
7878
Set<String> onlineServers = QueueTestUtils.onlineServers(group.queueServers().toArray(String[]::new));
79-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
79+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
8080
QueueCleaner cleaner = new QueueCleaner(environment);
8181

8282
cleaner.cleanGroup(group);
@@ -90,7 +90,7 @@ void removesMultipleStaleEntries() {
9090
QueueTestUtils.TestQueuePlugin plugin = new QueueTestUtils.TestQueuePlugin(config);
9191
QueueGroup group = QueueTestUtils.defaultGroup(config);
9292
Set<String> onlineServers = QueueTestUtils.onlineServers(group.queueServers().toArray(String[]::new));
93-
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, onlineServers);
93+
QueueEnvironment environment = new QueueEnvironment(plugin, plugin::getConfiguration, () -> onlineServers);
9494
QueueCleaner cleaner = new QueueCleaner(environment);
9595

9696
QueueType type = QueueTestUtils.defaultQueueType(config);

0 commit comments

Comments
 (0)