Commit 3f97bb682a04c25a64a221b07fc6f4a048a99ede

Authored by Sergey Matvienko
1 parent 193c0ce6

executors: names added, shutdownNow for some executors to prevent memory leaks d…

…uring lifecycle (mostly affects the test runner JVM)
... ... @@ -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
... ...
... ... @@ -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());
... ...