Commit 3f97bb682a04c25a64a221b07fc6f4a048a99ede
1 parent
193c0ce6
executors: names added, shutdownNow for some executors to prevent memory leaks d…
…uring lifecycle (mostly affects the test runner JVM)
Showing
10 changed files
with
76 additions
and
24 deletions
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
... | ... | @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; |
23 | 23 | import org.springframework.beans.factory.annotation.Value; |
24 | 24 | import org.springframework.context.annotation.Lazy; |
25 | 25 | import org.springframework.stereotype.Service; |
26 | +import org.thingsboard.common.util.ThingsBoardExecutors; | |
26 | 27 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
27 | 28 | import org.thingsboard.rule.engine.api.MailService; |
28 | 29 | import org.thingsboard.server.common.data.ApiFeature; |
... | ... | @@ -486,7 +487,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
486 | 487 | log.info("Initializing tenant states."); |
487 | 488 | updateLock.lock(); |
488 | 489 | try { |
489 | - ExecutorService tmpInitExecutor = Executors.newWorkStealingPool(20); | |
490 | + ExecutorService tmpInitExecutor = ThingsBoardExecutors.newWorkStealingPool(20, "init-tenant-states-from-db"); | |
490 | 491 | try { |
491 | 492 | PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, 1024); |
492 | 493 | List<Future<?>> futures = new ArrayList<>(); | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | 20 | import org.springframework.beans.factory.annotation.Autowired; |
21 | 21 | import org.springframework.stereotype.Service; |
22 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
22 | 23 | import org.thingsboard.server.common.data.edge.Edge; |
23 | 24 | import org.thingsboard.server.common.data.edge.EdgeEvent; |
24 | 25 | import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
... | ... | @@ -79,7 +80,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { |
79 | 80 | |
80 | 81 | @PostConstruct |
81 | 82 | public void initExecutor() { |
82 | - tsCallBackExecutor = Executors.newSingleThreadExecutor(); | |
83 | + tsCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-notifications")); | |
83 | 84 | } |
84 | 85 | |
85 | 86 | @PreDestroy | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import org.eclipse.leshan.core.node.LwM2mResource; |
23 | 23 | import org.eclipse.leshan.core.response.ExecuteResponse; |
24 | 24 | import org.eclipse.leshan.core.response.ReadResponse; |
25 | 25 | import org.eclipse.leshan.core.response.WriteResponse; |
26 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
26 | 27 | |
27 | 28 | import javax.security.auth.Destroyable; |
28 | 29 | import java.util.Arrays; |
... | ... | @@ -37,7 +38,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { |
37 | 38 | |
38 | 39 | private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 5, 6, 7, 9); |
39 | 40 | |
40 | - private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); | |
41 | + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName())); | |
41 | 42 | |
42 | 43 | private final AtomicInteger state = new AtomicInteger(0); |
43 | 44 | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import org.eclipse.leshan.core.node.LwM2mResource; |
24 | 24 | import org.eclipse.leshan.core.response.ExecuteResponse; |
25 | 25 | import org.eclipse.leshan.core.response.ReadResponse; |
26 | 26 | import org.eclipse.leshan.core.response.WriteResponse; |
27 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
27 | 28 | |
28 | 29 | import javax.security.auth.Destroyable; |
29 | 30 | import java.util.Arrays; |
... | ... | @@ -38,7 +39,7 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { |
38 | 39 | |
39 | 40 | private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 4, 6, 7, 9); |
40 | 41 | |
41 | - private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); | |
42 | + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName())); | |
42 | 43 | |
43 | 44 | private final AtomicInteger state = new AtomicInteger(0); |
44 | 45 | ... | ... |
... | ... | @@ -17,10 +17,12 @@ package org.thingsboard.server.util; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.MoreExecutors; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | +import org.junit.After; | |
20 | 21 | import org.junit.Test; |
21 | 22 | import org.junit.runner.RunWith; |
22 | 23 | import org.mockito.Mockito; |
23 | 24 | import org.mockito.junit.MockitoJUnitRunner; |
25 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
24 | 26 | import org.thingsboard.server.utils.EventDeduplicationExecutor; |
25 | 27 | |
26 | 28 | import java.util.concurrent.ExecutorService; |
... | ... | @@ -31,6 +33,16 @@ import java.util.function.Consumer; |
31 | 33 | @RunWith(MockitoJUnitRunner.class) |
32 | 34 | public class EventDeduplicationExecutorTest { |
33 | 35 | |
36 | + ThingsBoardThreadFactory threadFactory = ThingsBoardThreadFactory.forName(getClass().getSimpleName()); | |
37 | + ExecutorService executor; | |
38 | + | |
39 | + @After | |
40 | + public void tearDown() throws Exception { | |
41 | + if (executor != null) { | |
42 | + executor.shutdownNow(); | |
43 | + } | |
44 | + } | |
45 | + | |
34 | 46 | @Test |
35 | 47 | public void testSimpleFlowSameThread() throws InterruptedException { |
36 | 48 | simpleFlow(MoreExecutors.newDirectExecutorService()); |
... | ... | @@ -48,32 +60,38 @@ public class EventDeduplicationExecutorTest { |
48 | 60 | |
49 | 61 | @Test |
50 | 62 | public void testSimpleFlowSingleThread() throws InterruptedException { |
51 | - simpleFlow(Executors.newSingleThreadExecutor()); | |
63 | + executor = Executors.newSingleThreadExecutor(threadFactory); | |
64 | + simpleFlow(executor); | |
52 | 65 | } |
53 | 66 | |
54 | 67 | @Test |
55 | 68 | public void testPeriodicFlowSingleThread() throws InterruptedException { |
56 | - periodicFlow(Executors.newSingleThreadExecutor()); | |
69 | + executor = Executors.newSingleThreadExecutor(threadFactory); | |
70 | + periodicFlow(executor); | |
57 | 71 | } |
58 | 72 | |
59 | 73 | @Test |
60 | 74 | public void testExceptionFlowSingleThread() throws InterruptedException { |
61 | - exceptionFlow(Executors.newSingleThreadExecutor()); | |
75 | + executor = Executors.newSingleThreadExecutor(threadFactory); | |
76 | + exceptionFlow(executor); | |
62 | 77 | } |
63 | 78 | |
64 | 79 | @Test |
65 | 80 | public void testSimpleFlowMultiThread() throws InterruptedException { |
66 | - simpleFlow(Executors.newFixedThreadPool(3)); | |
81 | + executor = Executors.newFixedThreadPool(3, threadFactory); | |
82 | + simpleFlow(executor); | |
67 | 83 | } |
68 | 84 | |
69 | 85 | @Test |
70 | 86 | public void testPeriodicFlowMultiThread() throws InterruptedException { |
71 | - periodicFlow(Executors.newFixedThreadPool(3)); | |
87 | + executor = Executors.newFixedThreadPool(3, threadFactory); | |
88 | + periodicFlow(executor); | |
72 | 89 | } |
73 | 90 | |
74 | 91 | @Test |
75 | 92 | public void testExceptionFlowMultiThread() throws InterruptedException { |
76 | - exceptionFlow(Executors.newFixedThreadPool(3)); | |
93 | + executor = Executors.newFixedThreadPool(3, threadFactory); | |
94 | + exceptionFlow(executor); | |
77 | 95 | } |
78 | 96 | |
79 | 97 | private void simpleFlow(ExecutorService executorService) throws InterruptedException { | ... | ... |
... | ... | @@ -22,6 +22,8 @@ import org.junit.Before; |
22 | 22 | import org.junit.Test; |
23 | 23 | import org.junit.runner.RunWith; |
24 | 24 | import org.mockito.junit.MockitoJUnitRunner; |
25 | +import org.thingsboard.common.util.ThingsBoardExecutors; | |
26 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
25 | 27 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | 28 | |
27 | 29 | import java.util.ArrayList; |
... | ... | @@ -45,6 +47,7 @@ public class ActorSystemTest { |
45 | 47 | |
46 | 48 | private volatile TbActorSystem actorSystem; |
47 | 49 | private volatile ExecutorService submitPool; |
50 | + private ExecutorService executor; | |
48 | 51 | private int parallelism; |
49 | 52 | |
50 | 53 | @Before |
... | ... | @@ -60,47 +63,57 @@ public class ActorSystemTest { |
60 | 63 | public void shutdownActorSystem() { |
61 | 64 | actorSystem.stop(); |
62 | 65 | submitPool.shutdownNow(); |
66 | + if (executor != null) { | |
67 | + executor.shutdownNow(); | |
68 | + } | |
63 | 69 | } |
64 | 70 | |
65 | 71 | @Test |
66 | 72 | public void test1actorsAnd100KMessages() throws InterruptedException { |
67 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
73 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
74 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
68 | 75 | testActorsAndMessages(1, _100K, 1); |
69 | 76 | } |
70 | 77 | |
71 | 78 | @Test |
72 | 79 | public void test10actorsAnd100KMessages() throws InterruptedException { |
73 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
80 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
81 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
74 | 82 | testActorsAndMessages(10, _100K, 1); |
75 | 83 | } |
76 | 84 | |
77 | 85 | @Test |
78 | 86 | public void test100KActorsAnd1Messages5timesSingleThread() throws InterruptedException { |
79 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newSingleThreadExecutor()); | |
87 | + executor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName())); | |
88 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
80 | 89 | testActorsAndMessages(_100K, 1, 5); |
81 | 90 | } |
82 | 91 | |
83 | 92 | @Test |
84 | 93 | public void test100KActorsAnd1Messages5times() throws InterruptedException { |
85 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
94 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
95 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
86 | 96 | testActorsAndMessages(_100K, 1, 5); |
87 | 97 | } |
88 | 98 | |
89 | 99 | @Test |
90 | 100 | public void test100KActorsAnd10Messages() throws InterruptedException { |
91 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
101 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
102 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
92 | 103 | testActorsAndMessages(_100K, 10, 1); |
93 | 104 | } |
94 | 105 | |
95 | 106 | @Test |
96 | 107 | public void test1KActorsAnd1KMessages() throws InterruptedException { |
97 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
108 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
109 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
98 | 110 | testActorsAndMessages(1000, 1000, 10); |
99 | 111 | } |
100 | 112 | |
101 | 113 | @Test |
102 | 114 | public void testNoMessagesAfterDestroy() throws InterruptedException { |
103 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
115 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
116 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
104 | 117 | ActorTestCtx testCtx1 = getActorTestCtx(1); |
105 | 118 | ActorTestCtx testCtx2 = getActorTestCtx(1); |
106 | 119 | |
... | ... | @@ -119,7 +132,8 @@ public class ActorSystemTest { |
119 | 132 | |
120 | 133 | @Test |
121 | 134 | public void testOneActorCreated() throws InterruptedException { |
122 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
135 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
136 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
123 | 137 | ActorTestCtx testCtx1 = getActorTestCtx(1); |
124 | 138 | ActorTestCtx testCtx2 = getActorTestCtx(1); |
125 | 139 | TbActorId actorId = new TbEntityActorId(new DeviceId(UUID.randomUUID())); |
... | ... | @@ -145,7 +159,8 @@ public class ActorSystemTest { |
145 | 159 | |
146 | 160 | @Test |
147 | 161 | public void testActorCreatorCalledOnce() throws InterruptedException { |
148 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
162 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
163 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
149 | 164 | ActorTestCtx testCtx = getActorTestCtx(1); |
150 | 165 | TbActorId actorId = new TbEntityActorId(new DeviceId(UUID.randomUUID())); |
151 | 166 | final int actorsCount = 1000; |
... | ... | @@ -169,7 +184,8 @@ public class ActorSystemTest { |
169 | 184 | |
170 | 185 | @Test |
171 | 186 | public void testFailedInit() throws InterruptedException { |
172 | - actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism)); | |
187 | + executor = ThingsBoardExecutors.newWorkStealingPool(parallelism, getClass()); | |
188 | + actorSystem.createDispatcher(ROOT_DISPATCHER, executor); | |
173 | 189 | ActorTestCtx testCtx1 = getActorTestCtx(1); |
174 | 190 | ActorTestCtx testCtx2 = getActorTestCtx(1); |
175 | 191 | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import org.eclipse.californium.scandium.DTLSConnector; |
24 | 24 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
25 | 25 | import org.springframework.beans.factory.annotation.Autowired; |
26 | 26 | import org.springframework.stereotype.Component; |
27 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
27 | 28 | |
28 | 29 | import javax.annotation.PostConstruct; |
29 | 30 | import javax.annotation.PreDestroy; |
... | ... | @@ -118,7 +119,7 @@ public class DefaultCoapServerService implements CoapServerService { |
118 | 119 | CoapEndpoint dtlsCoapEndpoint = dtlsCoapEndpointBuilder.build(); |
119 | 120 | server.addEndpoint(dtlsCoapEndpoint); |
120 | 121 | tbDtlsCertificateVerifier = (TbCoapDtlsCertificateVerifier) dtlsConnectorConfig.getAdvancedCertificateVerifier(); |
121 | - dtlsSessionsExecutor = Executors.newSingleThreadScheduledExecutor(); | |
122 | + dtlsSessionsExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName())); | |
122 | 123 | dtlsSessionsExecutor.scheduleAtFixedRate(this::evictTimeoutSessions, new Random().nextInt((int) getDtlsSessionReportTimeout()), getDtlsSessionReportTimeout(), TimeUnit.MILLISECONDS); |
123 | 124 | } |
124 | 125 | Resource root = server.getRoot(); | ... | ... |
... | ... | @@ -34,6 +34,7 @@ import org.snmp4j.transport.DefaultTcpTransportMapping; |
34 | 34 | import org.snmp4j.transport.DefaultUdpTransportMapping; |
35 | 35 | import org.springframework.beans.factory.annotation.Value; |
36 | 36 | import org.springframework.stereotype.Service; |
37 | +import org.thingsboard.common.util.ThingsBoardExecutors; | |
37 | 38 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
38 | 39 | import org.thingsboard.server.common.data.DataConstants; |
39 | 40 | import org.thingsboard.server.common.data.TbTransportService; |
... | ... | @@ -90,7 +91,7 @@ public class SnmpTransportService implements TbTransportService { |
90 | 91 | @PostConstruct |
91 | 92 | private void init() throws IOException { |
92 | 93 | queryingExecutor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), ThingsBoardThreadFactory.forName("snmp-querying")); |
93 | - responseProcessingExecutor = Executors.newWorkStealingPool(responseProcessingParallelismLevel); | |
94 | + responseProcessingExecutor = ThingsBoardExecutors.newWorkStealingPool(responseProcessingParallelismLevel, "snmp-response-processing"); | |
94 | 95 | |
95 | 96 | initializeSnmp(); |
96 | 97 | configureResponseDataMappers(); |
... | ... | @@ -99,6 +100,16 @@ public class SnmpTransportService implements TbTransportService { |
99 | 100 | log.info("SNMP transport service initialized"); |
100 | 101 | } |
101 | 102 | |
103 | + @PreDestroy | |
104 | + public void stop() { | |
105 | + if (queryingExecutor != null) { | |
106 | + queryingExecutor.shutdownNow(); | |
107 | + } | |
108 | + if (responseProcessingExecutor != null) { | |
109 | + responseProcessingExecutor.shutdownNow(); | |
110 | + } | |
111 | + } | |
112 | + | |
102 | 113 | private void initializeSnmp() throws IOException { |
103 | 114 | TransportMapping<?> transportMapping; |
104 | 115 | switch (snmpUnderlyingProtocol) { | ... | ... |
... | ... | @@ -263,7 +263,7 @@ public class MqttClientTest extends AbstractContainerTest { |
263 | 263 | JsonObject serverRpcPayload = new JsonObject(); |
264 | 264 | serverRpcPayload.addProperty("method", "getValue"); |
265 | 265 | serverRpcPayload.addProperty("params", true); |
266 | - ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); | |
266 | + ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName()))); | |
267 | 267 | ListenableFuture<ResponseEntity> future = service.submit(() -> { |
268 | 268 | try { |
269 | 269 | return restClient.getRestTemplate() |
... | ... | @@ -287,6 +287,7 @@ public class MqttClientTest extends AbstractContainerTest { |
287 | 287 | mqttClient.publish("v1/devices/me/rpc/response/" + requestId, Unpooled.wrappedBuffer(clientResponse.toString().getBytes())).get(); |
288 | 288 | |
289 | 289 | ResponseEntity serverResponse = future.get(5, TimeUnit.SECONDS); |
290 | + service.shutdownNow(); | |
290 | 291 | Assert.assertTrue(serverResponse.getStatusCode().is2xxSuccessful()); |
291 | 292 | Assert.assertEquals(clientResponse.toString(), serverResponse.getBody()); |
292 | 293 | ... | ... |
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java
... | ... | @@ -259,7 +259,7 @@ public class MqttGatewayClientTest extends AbstractContainerTest { |
259 | 259 | JsonObject serverRpcPayload = new JsonObject(); |
260 | 260 | serverRpcPayload.addProperty("method", "getValue"); |
261 | 261 | serverRpcPayload.addProperty("params", true); |
262 | - ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); | |
262 | + ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName()))); | |
263 | 263 | ListenableFuture<ResponseEntity> future = service.submit(() -> { |
264 | 264 | try { |
265 | 265 | return restClient.getRestTemplate() |
... | ... | @@ -273,6 +273,7 @@ public class MqttGatewayClientTest extends AbstractContainerTest { |
273 | 273 | |
274 | 274 | // Wait for RPC call from the server and send the response |
275 | 275 | MqttEvent requestFromServer = listener.getEvents().poll(10, TimeUnit.SECONDS); |
276 | + service.shutdownNow(); | |
276 | 277 | |
277 | 278 | Assert.assertNotNull(requestFromServer); |
278 | 279 | Assert.assertNotNull(requestFromServer.getMessage()); | ... | ... |