Skip to content

Commit b543e6c

Browse files
authored
Improve update check (#972)
* Use non-critical IO Pool for resolving versions As the version resolution is not critical it's likely better to have it here. The previously used `backgroundExecutor` is used for internal resource reloading during game initialization which can cause it to get stuck when the download hangs (e.g. when using 3rd party mods that modify resource reloading like Continuity) * Do not block thread until update checks are finished - Improve how update checking is executed (thanks litetex)
1 parent 5423451 commit b543e6c

1 file changed

Lines changed: 71 additions & 69 deletions

File tree

src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java

Lines changed: 71 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.time.format.DateTimeParseException;
2828
import java.util.*;
2929
import java.util.concurrent.ExecutionException;
30+
import java.util.concurrent.ExecutorService;
3031
import java.util.concurrent.Executors;
3132

3233
public class UpdateCheckerUtil {
@@ -44,92 +45,93 @@ public static void checkForUpdates() {
4445
}
4546

4647
LOGGER.info("Checking mod updates...");
47-
Util.backgroundExecutor().execute(UpdateCheckerUtil::checkForUpdates0);
48+
Util.nonCriticalIoPool().execute(UpdateCheckerUtil::checkForUpdates0);
4849
}
4950

5051
private static void checkForUpdates0() {
51-
try (var executor = Executors.newThreadPerTaskExecutor(new UpdateCheckerThreadFactory())) {
52-
List<Mod> withoutUpdateChecker = new ArrayList<>();
53-
54-
List<Mod> updatableMods = ModMenu.MODS.values()
55-
.stream()
56-
.filter(UpdateCheckerUtil::allowsUpdateChecks)
57-
.toList();
58-
59-
for (Mod mod : updatableMods) {
60-
UpdateChecker updateChecker = mod.getUpdateChecker();
61-
62-
if (updateChecker == null) {
63-
withoutUpdateChecker.add(mod); // Fall back to update checking via Modrinth
64-
} else {
65-
executor.submit(() -> {
66-
// We don't know which mod the thread is for yet in the thread factory
67-
Thread.currentThread().setName("ModMenu/Update Checker/%s".formatted(mod.getName()));
68-
69-
var update = updateChecker.checkForUpdates();
70-
mod.setUpdateInfo(update);
71-
72-
if (update != null && update.isUpdateAvailable()) {
73-
LOGGER.info("Update available for '{}@{}'", mod.getId(), mod.getVersion());
74-
}
75-
});
76-
}
52+
// noinspection resource - close would result in waiting for all thread, use shutdown instead
53+
ExecutorService executor = Executors.newThreadPerTaskExecutor(new UpdateCheckerThreadFactory());
54+
List<Mod> withoutUpdateChecker = new ArrayList<>();
55+
56+
List<Mod> updatableMods = ModMenu.MODS.values()
57+
.stream()
58+
.filter(UpdateCheckerUtil::allowsUpdateChecks)
59+
.toList();
60+
61+
for (Mod mod : updatableMods) {
62+
UpdateChecker updateChecker = mod.getUpdateChecker();
63+
64+
if (updateChecker == null) {
65+
withoutUpdateChecker.add(mod); // Fall back to update checking via Modrinth
66+
} else {
67+
executor.submit(() -> {
68+
// We don't know which mod the thread is for yet in the thread factory
69+
Thread.currentThread().setName("ModMenu/Update Checker/%s".formatted(mod.getName()));
70+
71+
var update = updateChecker.checkForUpdates();
72+
mod.setUpdateInfo(update);
73+
74+
if (update != null && update.isUpdateAvailable()) {
75+
LOGGER.info("Update available for '{}@{}'", mod.getId(), mod.getVersion());
76+
}
77+
});
7778
}
79+
}
7880

79-
if (modrinthApiV2Deprecated) {
80-
return;
81-
}
81+
if (modrinthApiV2Deprecated) {
82+
return;
83+
}
8284

83-
var modHashes = getModHashes(withoutUpdateChecker);
85+
var modHashes = getModHashes(withoutUpdateChecker);
8486

85-
var currentVersionsFuture = executor.submit(() -> getCurrentVersions(modHashes.keySet()));
86-
var updatedVersionsFuture = executor.submit(() -> getUpdatedVersions(modHashes.keySet()));
87+
var currentVersionsFuture = executor.submit(() -> getCurrentVersions(modHashes.keySet()));
88+
var updatedVersionsFuture = executor.submit(() -> getUpdatedVersions(modHashes.keySet()));
8789

88-
Map<String, Instant> currentVersions = null;
89-
Map<String, VersionUpdate> updatedVersions = null;
90+
Map<String, Instant> currentVersions = null;
91+
Map<String, VersionUpdate> updatedVersions = null;
9092

91-
try {
92-
currentVersions = currentVersionsFuture.get();
93-
updatedVersions = updatedVersionsFuture.get();
94-
} catch (ExecutionException e) {
95-
throw new RuntimeException(e);
96-
} catch (InterruptedException e) {
97-
Thread.currentThread().interrupt();
98-
}
93+
try {
94+
currentVersions = currentVersionsFuture.get();
95+
updatedVersions = updatedVersionsFuture.get();
96+
} catch (ExecutionException e) {
97+
throw new RuntimeException(e);
98+
} catch (InterruptedException e) {
99+
Thread.currentThread().interrupt();
100+
}
99101

100-
if (currentVersions == null || updatedVersions == null) {
101-
return;
102-
}
102+
if (currentVersions == null || updatedVersions == null) {
103+
return;
104+
}
103105

104-
for (var hash : modHashes.keySet()) {
105-
var date = currentVersions.get(hash);
106-
var data = updatedVersions.get(hash);
106+
for (var hash : modHashes.keySet()) {
107+
var date = currentVersions.get(hash);
108+
var data = updatedVersions.get(hash);
107109

108-
if (date == null || data == null) {
109-
continue;
110-
}
110+
if (date == null || data == null) {
111+
continue;
112+
}
111113

112-
// Current version is still the newest
113-
if (Objects.equals(hash, data.hash)) {
114-
continue;
115-
}
114+
// Current version is still the newest
115+
if (Objects.equals(hash, data.hash)) {
116+
continue;
117+
}
116118

117-
// Current version is newer than what's
118-
// Available on our preferred update channel
119-
if (date.compareTo(data.releaseDate) >= 0) {
120-
continue;
121-
}
119+
// Current version is newer than what's
120+
// Available on our preferred update channel
121+
if (date.compareTo(data.releaseDate) >= 0) {
122+
continue;
123+
}
122124

123-
for (var mod : modHashes.get(hash)) {
124-
mod.setUpdateInfo(data.asUpdateInfo());
125-
LOGGER.info("Update available for '{}@{}', (-> {})",
126-
mod.getId(),
127-
mod.getVersion(),
128-
data.versionNumber
129-
);
130-
}
125+
for (var mod : modHashes.get(hash)) {
126+
mod.setUpdateInfo(data.asUpdateInfo());
127+
LOGGER.info("Update available for '{}@{}', (-> {})",
128+
mod.getId(),
129+
mod.getVersion(),
130+
data.versionNumber
131+
);
131132
}
132133
}
134+
executor.shutdown();
133135
}
134136

135137
private static Map<String, Set<Mod>> getModHashes(Collection<Mod> mods) {

0 commit comments

Comments
 (0)