Skip to content

Commit 25f598c

Browse files
Bugfix/fix resource leak in tests (#456)
* fix resource leak > fix duplicate instatiation of shutdown hooks * fix resource leak > add shutdown hooks to close/clear resources * fix resource leak > add shutdown hook for the ThreadPool of the MessageForwarderImple
1 parent 9cfaef2 commit 25f598c

File tree

6 files changed

+45
-25
lines changed

6 files changed

+45
-25
lines changed

hivemq-edge/src/main/java/com/hivemq/bootstrap/HiveMQExceptionHandlerBootstrap.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ static void handleUncaughtException(final Thread t, final Throwable e) {
5656
if (showException) {
5757
log.error("Cause: ", e);
5858
}
59+
} else if (rootCause instanceof ThreadDeath) {
60+
// NOOP: this happens when tests stop the remaining threads via thread.stop();
5961
} else {
6062
log.error("Uncaught Error:", e);
6163
}

hivemq-edge/src/main/java/com/hivemq/bridge/MessageForwarderImpl.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import com.google.common.util.concurrent.Futures;
2222
import com.google.common.util.concurrent.ListenableFuture;
2323
import com.google.common.util.concurrent.MoreExecutors;
24+
import com.hivemq.common.shutdown.HiveMQShutdownHook;
25+
import com.hivemq.common.shutdown.ShutdownHooks;
2426
import com.hivemq.configuration.HivemqId;
2527
import com.hivemq.configuration.service.InternalConfigurations;
2628
import com.hivemq.extension.sdk.api.annotations.NotNull;
@@ -77,11 +79,23 @@ public MessageForwarderImpl(
7779
final @NotNull LocalTopicTree topicTree,
7880
final @NotNull HivemqId hivemqId,
7981
final @NotNull Lazy<ClientQueuePersistence> queuePersistence,
80-
final @NotNull SingleWriterService singleWriterService) {
82+
final @NotNull SingleWriterService singleWriterService,
83+
final @NotNull ShutdownHooks shutdownHooks) {
8184
this.topicTree = topicTree;
8285
this.hivemqId = hivemqId;
8386
this.queuePersistence = queuePersistence;
8487
this.singleWriterService = singleWriterService;
88+
shutdownHooks.add(new HiveMQShutdownHook() {
89+
@Override
90+
public @NotNull String name() {
91+
return "MessageForwarder-Shutdown";
92+
}
93+
94+
@Override
95+
public void run() {
96+
executorService.shutdown();
97+
}
98+
});
8599
}
86100

87101
@Override

hivemq-edge/src/main/java/com/hivemq/common/shutdown/ShutdownHooks.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
import org.slf4j.LoggerFactory;
2525
import org.slf4j.MarkerFactory;
2626

27-
import javax.inject.Inject;
28-
import javax.inject.Singleton;
2927
import java.util.concurrent.Executors;
3028
import java.util.concurrent.ScheduledExecutorService;
3129
import java.util.concurrent.TimeUnit;
@@ -41,15 +39,13 @@
4139
*
4240
* @author Dominik Obermaier
4341
*/
44-
@Singleton
4542
public class ShutdownHooks {
4643

4744
private static final Logger log = LoggerFactory.getLogger(ShutdownHooks.class);
4845

4946
private final @NotNull AtomicBoolean shuttingDown;
5047
private final @NotNull Multimap</* Priority */Integer, HiveMQShutdownHook> synchronousHooks;
5148

52-
@Inject
5349
public ShutdownHooks() {
5450
shuttingDown = new AtomicBoolean(false);
5551

hivemq-edge/src/main/java/com/hivemq/edge/modules/ModuleLoader.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.slf4j.LoggerFactory;
2626

2727
import javax.inject.Inject;
28-
import javax.inject.Singleton;
2928
import java.io.File;
3029
import java.io.IOException;
3130
import java.net.URL;
@@ -34,15 +33,13 @@
3433
import java.util.List;
3534
import java.util.Set;
3635

37-
@Singleton
3836
public class ModuleLoader {
3937
private static final Logger log = LoggerFactory.getLogger(ModuleLoader.class);
4038

4139
private final @NotNull SystemInformation systemInformation;
4240
protected final @NotNull Set<EdgeModule> modules = new HashSet<>();
4341
private final @NotNull ClassServiceLoader classServiceLoader = new ClassServiceLoader();
4442

45-
@Inject
4643
public ModuleLoader(final @NotNull SystemInformation systemInformation) {
4744
this.systemInformation = systemInformation;
4845
}
@@ -93,7 +90,7 @@ protected void discoverWorkspaceModule(final File dir, final ClassLoader parentC
9390
}
9491
final IsolatedModuleClassloader isolatedClassloader =
9592
new IsolatedModuleClassloader(urls.toArray(new URL[0]), parentClassloader);
96-
modules.add(new EdgeModule(files[i], isolatedClassloader));
93+
modules.add(new EdgeModule(files[i], isolatedClassloader, true));
9794
} catch (final IOException ioException) {
9895
log.warn("Exception with reason {} while reading module file {}",
9996
ioException.getMessage(),
@@ -115,7 +112,7 @@ protected void loadFromModulesDirectory(final ClassLoader parentClassloader) {
115112
log.debug("Found module jar in modules lib {}.", lib.getAbsolutePath());
116113
final IsolatedModuleClassloader isolatedClassloader =
117114
new IsolatedModuleClassloader(new URL[]{lib.toURI().toURL()}, parentClassloader);
118-
modules.add(new EdgeModule(lib, isolatedClassloader));
115+
modules.add(new EdgeModule(lib, isolatedClassloader, true));
119116
} else {
120117
log.debug("Ignoring non jar file in module folder {}.", lib.getAbsolutePath());
121118
}
@@ -154,15 +151,19 @@ protected void loadFromModulesDirectory(final ClassLoader parentClassloader) {
154151
return modules;
155152
}
156153

154+
public void clear() {
155+
modules.clear();
156+
}
157+
157158
public static class EdgeModule {
158159

159160
private File root;
160161
private final @NotNull ClassLoader classloader;
161162

162-
public EdgeModule(final @NotNull File root, final @NotNull ClassLoader classloader) {
163+
public EdgeModule(final @NotNull File root, final @NotNull ClassLoader classloader, final boolean registerStaticResources) {
163164
this.classloader = classloader;
164165
this.root = root;
165-
if (classloader != null) {
166+
if (registerStaticResources) {
166167
AlternativeClassloadingStaticFileHandler.addClassLoader(classloader);
167168
}
168169
}

hivemq-edge/src/main/java/com/hivemq/http/JaxrsHttpServer.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public class JaxrsHttpServer {
6262
static final String MAX_RESP_TIME = "sun.net.httpserver.maxRspTime";
6363
private static final Logger logger = LoggerFactory.getLogger(JaxrsHttpServer.class);
6464
private final @NotNull List<HttpServer> httpServers = new ArrayList<>();
65+
private final @NotNull ShutdownHooks shutdownHooks;
6566
private final @NotNull List<JaxrsHttpServerConfiguration> configs;
6667
private final @Nullable ResourceConfig resourceConfig;
6768
private @Nullable JaxrsObjectMapperProvider objectMapperProvider;
@@ -72,6 +73,7 @@ public JaxrsHttpServer(
7273
final @NotNull ShutdownHooks shutdownHooks,
7374
final @NotNull List<JaxrsHttpServerConfiguration> configs,
7475
final @Nullable ResourceConfig resourceConfig) {
76+
this.shutdownHooks = shutdownHooks;
7577
this.configs = configs;
7678
this.resourceConfig = resourceConfig;
7779
shutdownHooks.add(new Shutdown());
@@ -181,7 +183,8 @@ public void startServer() {
181183
httpServer);
182184
registerContext("/module/images",
183185
new AlternativeClassloadingStaticFileHandler(objectMapperProvider.getMapper(),
184-
"httpd/images"),
186+
"httpd/images",
187+
shutdownHooks),
185188
httpServer);
186189

187190

hivemq-edge/src/main/java/com/hivemq/http/handlers/AlternativeClassloadingStaticFileHandler.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
package com.hivemq.http.handlers;
1717

1818
import com.fasterxml.jackson.databind.ObjectMapper;
19-
import com.hivemq.http.core.HttpUtils;
20-
import com.hivemq.http.core.IHttpRequestResponse;
19+
import com.hivemq.common.shutdown.HiveMQShutdownHook;
20+
import com.hivemq.common.shutdown.ShutdownHooks;
21+
import com.hivemq.extension.sdk.api.annotations.NotNull;
2122

22-
import java.io.IOException;
2323
import java.io.InputStream;
2424
import java.util.HashSet;
2525
import java.util.Iterator;
@@ -31,20 +31,24 @@
3131
* allowing modules to contribute arbitrary resources
3232
*/
3333
public class AlternativeClassloadingStaticFileHandler extends StaticFileHandler {
34-
protected static Set<ClassLoader> classLoaders;
34+
protected final static @NotNull Set<ClassLoader> classLoaders = new HashSet<>();;
3535

36-
public AlternativeClassloadingStaticFileHandler(ObjectMapper mapper, String resourceRoot) {
36+
public AlternativeClassloadingStaticFileHandler(ObjectMapper mapper, String resourceRoot, ShutdownHooks shutdownHooks) {
3737
super(mapper, resourceRoot);
38+
shutdownHooks.add(new HiveMQShutdownHook() {
39+
@Override
40+
public @NotNull String name() {
41+
return "AlternativeClassloadingStaticFileHandler - Shutdown";
42+
}
43+
44+
@Override
45+
public void run() {
46+
classLoaders.clear();
47+
}
48+
});
3849
}
3950

4051
public static void addClassLoader(ClassLoader classLoader){
41-
if(classLoaders == null){
42-
synchronized (AlternativeClassloadingStaticFileHandler.class){
43-
if(classLoaders == null){
44-
classLoaders = new HashSet<>();
45-
}
46-
}
47-
}
4852
classLoaders.add(classLoader);
4953
}
5054

0 commit comments

Comments
 (0)