Change everything to a central OkHttpClient, reduce amount of threads that can be used, adjust some other stuff

This commit is contained in:
Vankka 2022-08-22 18:46:12 +03:00
parent 9774eb5879
commit dbce0832a3
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
16 changed files with 152 additions and 52 deletions

View File

@ -1,3 +1,26 @@
/*
* This file is part of the DiscordSRV API, licensed under the MIT License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.discordsrv.api.discord.entity.interaction.command; package com.discordsrv.api.discord.entity.interaction.command;
import com.discordsrv.api.discord.entity.JDAEntity; import com.discordsrv.api.discord.entity.JDAEntity;

View File

@ -295,7 +295,7 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
builder.setContent(placeholders.apply(builder.getContent())); builder.setContent(placeholders.apply(builder.getContent()));
List<DiscordMessageEmbed> embeds = new ArrayList<>(builder.getEmbeds()); List<DiscordMessageEmbed> embeds = new ArrayList<>(builder.getEmbeds());
builder.getEmbeds().clear(); builder.getEmbeds().forEach(builder::removeEmbed);
for (DiscordMessageEmbed embed : embeds) { for (DiscordMessageEmbed embed : embeds) {
DiscordMessageEmbed.Builder embedBuilder = embed.toBuilder(); DiscordMessageEmbed.Builder embedBuilder = embed.toBuilder();

View File

@ -1,3 +1,26 @@
/*
* This file is part of the DiscordSRV API, licensed under the MIT License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.discordsrv.api.discord.events.interaction.command; package com.discordsrv.api.discord.events.interaction.command;
import com.discordsrv.api.discord.entity.DiscordUser; import com.discordsrv.api.discord.entity.DiscordUser;

View File

@ -1,3 +1,26 @@
/*
* This file is part of the DiscordSRV API, licensed under the MIT License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.discordsrv.api.discord.events.interaction.command; package com.discordsrv.api.discord.events.interaction.command;
import com.discordsrv.api.discord.entity.interaction.command.Command; import com.discordsrv.api.discord.entity.interaction.command.Command;

View File

@ -41,7 +41,7 @@ subprojects {
repositories { repositories {
// Snapshot repositories // Snapshot repositories
//maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } //maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
mavenLocal() //mavenLocal()
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' } maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
maven { maven {

View File

@ -120,7 +120,7 @@ public class VaultIntegration extends PluginIntegration<BukkitDiscordSRV> implem
} }
}; };
if (async) { if (async) {
discordSRV.scheduler().runFork(runnable); discordSRV.scheduler().run(runnable);
} else { } else {
discordSRV.scheduler().runOnMainThread(runnable); discordSRV.scheduler().runOnMainThread(runnable);
} }

View File

@ -40,7 +40,10 @@ dependencies {
api(libs.dependencydownload.runtime) api(libs.dependencydownload.runtime)
// Discord Webhooks // Discord Webhooks
runtimeDownloadApi(libs.webhooks) runtimeDownloadApi(libs.webhooks) {
// okhttp is already included
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
}
// Apache Commons // Apache Commons
runtimeDownloadApi(libs.commons.lang) runtimeDownloadApi(libs.commons.lang)

View File

@ -73,6 +73,9 @@ import com.discordsrv.common.storage.Storage;
import com.discordsrv.common.storage.StorageType; import com.discordsrv.common.storage.StorageType;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDAInfo;
import okhttp3.ConnectionPool;
import okhttp3.Dispatcher;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import org.intellij.lang.annotations.Language; import org.intellij.lang.annotations.Language;
@ -134,18 +137,7 @@ public abstract class AbstractDiscordSRV<B extends IBootstrap, C extends MainCon
private String gitRevision; private String gitRevision;
private String gitBranch; private String gitBranch;
private final OkHttpClient httpClient = new OkHttpClient.Builder() private OkHttpClient httpClient;
.addInterceptor(chain -> {
Request original = chain.request();
return chain.proceed(
original.newBuilder()
.removeHeader("User-Agent")
.addHeader("User-Agent", "DiscordSRV/" + version())
.build()
);
})
.callTimeout(1, TimeUnit.MINUTES)
.build();
private final ObjectMapper objectMapper = new ObjectMapper(); private final ObjectMapper objectMapper = new ObjectMapper();
// Internal // Internal
@ -174,6 +166,39 @@ public abstract class AbstractDiscordSRV<B extends IBootstrap, C extends MainCon
this.discordConnectionManager = new JDAConnectionManager(this); this.discordConnectionManager = new JDAConnectionManager(this);
this.channelConfig = new ChannelConfigHelper(this); this.channelConfig = new ChannelConfigHelper(this);
readManifest(); readManifest();
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(20); // Set maximum amount of requests at a time (to something more reasonable than 64)
dispatcher.setMaxRequestsPerHost(16); // Most requests are to discord.com
ConnectionPool connectionPool = new ConnectionPool(5, 10, TimeUnit.SECONDS);
this.httpClient = new OkHttpClient.Builder()
.dispatcher(dispatcher)
.connectionPool(connectionPool)
.addInterceptor(chain -> {
Request original = chain.request();
String host = original.url().host();
boolean isDiscord = host.endsWith("discord.com")
|| host.endsWith("discordapp.com")
|| host.endsWith("discord.gg");
String userAgent = isDiscord
? "DiscordBot (https://github.com/DiscordSRV/DiscordSRV, " + version() + ")"
+ " (" + JDAInfo.GITHUB + ", " + JDAInfo.VERSION + ")"
: "DiscordSRV/" + version();
return chain.proceed(
original.newBuilder()
.removeHeader("User-Agent")
.addHeader("User-Agent", userAgent)
.build()
);
})
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.build();
} }
protected URL getManifest() { protected URL getManifest() {

View File

@ -134,7 +134,7 @@ public interface DiscordSRV extends DiscordSRVApi {
@ApiStatus.NonExtendable @ApiStatus.NonExtendable
default <K, V> Caffeine<K, V> caffeineBuilder() { default <K, V> Caffeine<K, V> caffeineBuilder() {
return (Caffeine<K, V>) Caffeine.newBuilder() return (Caffeine<K, V>) Caffeine.newBuilder()
.executor(scheduler().forkJoinPool()); .executor(scheduler().executorService());
} }
OkHttpClient httpClient(); OkHttpClient httpClient();
ObjectMapper json(); ObjectMapper json();

View File

@ -450,7 +450,7 @@ public class DiscordAPIImpl implements DiscordAPI {
@Override @Override
public Command.RegistrationResult registerCommand(Command command) { public Command.RegistrationResult registerCommand(Command command) {
return commandRegistry.register(command); return commandRegistry.register(command, false);
} }
@Override @Override

View File

@ -1,3 +1,21 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.common.discord.api; package com.discordsrv.common.discord.api;
import com.discordsrv.api.discord.entity.JDAEntity; import com.discordsrv.api.discord.entity.JDAEntity;

View File

@ -52,8 +52,6 @@ import net.dv8tion.jda.api.utils.ChunkingFilter;
import net.dv8tion.jda.api.utils.MemberCachePolicy; import net.dv8tion.jda.api.utils.MemberCachePolicy;
import net.dv8tion.jda.internal.entities.ReceivedMessage; import net.dv8tion.jda.internal.entities.ReceivedMessage;
import net.dv8tion.jda.internal.hooks.EventManagerProxy; import net.dv8tion.jda.internal.hooks.EventManagerProxy;
import net.dv8tion.jda.internal.utils.IOUtil;
import okhttp3.OkHttpClient;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
@ -271,13 +269,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
jdaBuilder.setCallbackPool(discordSRV.scheduler().forkJoinPool()); jdaBuilder.setCallbackPool(discordSRV.scheduler().forkJoinPool());
jdaBuilder.setGatewayPool(gatewayPool); jdaBuilder.setGatewayPool(gatewayPool);
jdaBuilder.setRateLimitPool(rateLimitPool, true); jdaBuilder.setRateLimitPool(rateLimitPool, true);
jdaBuilder.setHttpClient(discordSRV.httpClient());
OkHttpClient.Builder httpBuilder = IOUtil.newHttpClientBuilder();
// These 3 are 10 seconds by default
httpBuilder.connectTimeout(20, TimeUnit.SECONDS);
httpBuilder.readTimeout(20, TimeUnit.SECONDS);
httpBuilder.writeTimeout(20, TimeUnit.SECONDS);
jdaBuilder.setHttpClientBuilder(httpBuilder);
WebSocketFactory webSocketFactory = new WebSocketFactory(); WebSocketFactory webSocketFactory = new WebSocketFactory();
jdaBuilder.setWebsocketFactory(webSocketFactory); jdaBuilder.setWebsocketFactory(webSocketFactory);

View File

@ -23,7 +23,6 @@ import net.dv8tion.jda.api.events.GenericEvent;
import net.dv8tion.jda.api.hooks.IEventManager; import net.dv8tion.jda.api.hooks.IEventManager;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List; import java.util.List;
public class JDAEventManager implements IEventManager { public class JDAEventManager implements IEventManager {
@ -34,8 +33,10 @@ public class JDAEventManager implements IEventManager {
this.discordSRV = discordSRV; this.discordSRV = discordSRV;
} }
private void illegalUse() { @SuppressWarnings("UnusedReturnValue")
throw new RuntimeException("The JDA event manager may not be used while using DiscordSRV. Please use DiscordSRV's own event bus to listen for JDA events"); private <T> T illegalUse() {
throw new RuntimeException("The JDA event manager may not be used while using DiscordSRV. "
+ "Please use DiscordSRV's own event bus to listen for JDA events");
} }
@Override @Override
@ -56,6 +57,6 @@ public class JDAEventManager implements IEventManager {
@NotNull @NotNull
@Override @Override
public List<Object> getRegisteredListeners() { public List<Object> getRegisteredListeners() {
return Collections.emptyList(); return illegalUse();
} }
} }

View File

@ -43,14 +43,14 @@ public abstract class AbstractPlayerProvider<T extends IPlayer, DT extends Disco
protected void addPlayer(UUID uuid, T player, boolean initial) { protected void addPlayer(UUID uuid, T player, boolean initial) {
this.players.put(uuid, player); this.players.put(uuid, player);
this.allPlayers.add(player); this.allPlayers.add(player);
discordSRV.scheduler().runFork(() -> discordSRV.eventBus().publish(new PlayerConnectedEvent(player, initial))); discordSRV.scheduler().run(() -> discordSRV.eventBus().publish(new PlayerConnectedEvent(player, initial)));
} }
protected void removePlayer(UUID uuid) { protected void removePlayer(UUID uuid) {
T player = this.players.remove(uuid); T player = this.players.remove(uuid);
if (player != null) { if (player != null) {
allPlayers.remove(player); allPlayers.remove(player);
discordSRV.scheduler().runFork(() -> discordSRV.eventBus().publish(new PlayerDisconnectedEvent(player))); discordSRV.scheduler().run(() -> discordSRV.eventBus().publish(new PlayerDisconnectedEvent(player)));
} }
} }

View File

@ -62,15 +62,6 @@ public interface Scheduler {
*/ */
Future<?> run(@NotNull Runnable task); Future<?> run(@NotNull Runnable task);
/**
* Runs the provided {@link Runnable} on a {@link ForkJoinPool} as soon as possible.
* Please view the docs of {@link ForkJoinPool} for benefits.
*
* @param task the task
*/
@ApiStatus.NonExtendable
ForkJoinTask<?> runFork(@NotNull Runnable task);
/** /**
* Schedules the given task to run after the provided time in the provided {@link TimeUnit}. * Schedules the given task to run after the provided time in the provided {@link TimeUnit}.
* *

View File

@ -40,18 +40,24 @@ public class StandardScheduler implements Scheduler {
this( this(
discordSRV, discordSRV,
new ThreadPoolExecutor( new ThreadPoolExecutor(
4, /* Core pool size */ 1, /* Core pool size */
16, /* Max pool size */ 20, /* Max pool size */
60, TimeUnit.SECONDS, /* Timeout */ 60, TimeUnit.SECONDS, /* Timeout */
new SynchronousQueue<>(), new SynchronousQueue<>(),
new CountingThreadFactory(Scheduler.THREAD_NAME_PREFIX + "Executor #%s") new CountingThreadFactory(Scheduler.THREAD_NAME_PREFIX + "Executor #%s")
), ),
new ScheduledThreadPoolExecutor( new ScheduledThreadPoolExecutor(
2, /* Core pool size */ 0, /* Core pool size */
new CountingThreadFactory(Scheduler.THREAD_NAME_PREFIX + "Scheduled Executor #%s") new CountingThreadFactory(Scheduler.THREAD_NAME_PREFIX + "Scheduled Executor #%s")
), ),
new ForkJoinPool( new ForkJoinPool(
Math.max(1, Runtime.getRuntime().availableProcessors() - 1), /* Parallelism - not core pool size */ /* parallelism */
Math.min(
/* max of 10 */
10,
/* cpu cores - 1 or at least 1 */
Math.max(1, Runtime.getRuntime().availableProcessors() - 1)
),
new CountingForkJoinWorkerThreadFactory(Scheduler.THREAD_NAME_PREFIX + "ForkJoinPool Worker #%s"), new CountingForkJoinWorkerThreadFactory(Scheduler.THREAD_NAME_PREFIX + "ForkJoinPool Worker #%s"),
null, null,
false /* FIFO */ false /* FIFO */
@ -113,11 +119,6 @@ public class StandardScheduler implements Scheduler {
return executorService.submit(wrap(task)); return executorService.submit(wrap(task));
} }
@Override
public ForkJoinTask<?> runFork(@NotNull Runnable task) {
return forkJoinPool.submit(wrap(task));
}
@Override @Override
public ScheduledFuture<?> runLater(Runnable task, long timeMillis) { public ScheduledFuture<?> runLater(Runnable task, long timeMillis) {
return scheduledExecutorService.schedule(wrap(task), timeMillis, TimeUnit.MILLISECONDS); return scheduledExecutorService.schedule(wrap(task), timeMillis, TimeUnit.MILLISECONDS);
@ -132,7 +133,7 @@ public class StandardScheduler implements Scheduler {
@Override @Override
public void execute(@NotNull Runnable command) { public void execute(@NotNull Runnable command) {
runFork(command); run(command);
} }
} }
} }