diff --git a/backend/commons/src/main/java/org/sonarsource/sonarlint/core/commons/util/FailSafeExecutors.java b/backend/commons/src/main/java/org/sonarsource/sonarlint/core/commons/util/FailSafeExecutors.java new file mode 100644 index 0000000000..68035cf543 --- /dev/null +++ b/backend/commons/src/main/java/org/sonarsource/sonarlint/core/commons/util/FailSafeExecutors.java @@ -0,0 +1,106 @@ +/* + * SonarLint Core - Commons + * Copyright (C) 2016-2025 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarsource.sonarlint.core.commons.util; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.FutureTask; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; + +/** + * This class should always be preferred to {@link java.util.concurrent.Executors}, except for a few cases regarding RPC read/write threads. + */ +public class FailSafeExecutors { + private static final SonarLintLogger LOG = SonarLintLogger.get(); + + private FailSafeExecutors() { + // utility class + } + + public static ExecutorService newSingleThreadExecutor(String threadName) { + return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), r -> new Thread(r, threadName)) { + @Override + protected void afterExecute(Runnable task, @Nullable Throwable throwable) { + var extractedThrowable = extractThrowable(task, throwable); + if (extractedThrowable != null) { + LOG.error("An error occurred while executing a task in " + threadName, extractedThrowable); + } + super.afterExecute(task, throwable); + } + }; + } + + public static ScheduledExecutorService newSingleThreadScheduledExecutor(String threadName) { + return new ScheduledThreadPoolExecutor(1, r -> new Thread(r, threadName)) { + @Override + protected void afterExecute(Runnable task, @Nullable Throwable throwable) { + var extractedThrowable = extractThrowable(task, throwable); + if (extractedThrowable != null) { + LOG.error("An error occurred while executing a scheduled task in " + threadName, extractedThrowable); + } + super.afterExecute(task, throwable); + } + }; + } + + public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { + return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>(), threadFactory) { + @Override + protected void afterExecute(Runnable task, @Nullable Throwable throwable) { + var extractedThrowable = extractThrowable(task, throwable); + if (extractedThrowable != null) { + LOG.error("An error occurred while executing a task in " + Thread.currentThread(), extractedThrowable); + } + super.afterExecute(task, throwable); + } + }; + } + + @CheckForNull + private static Throwable extractThrowable(Runnable task, @Nullable Throwable throwable) { + if (throwable != null) { + return throwable; + } + if (task instanceof FutureTask futureTask) { + try { + if (futureTask.isDone() && !futureTask.isCancelled()) { + futureTask.get(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + return e.getCause(); + } catch (CancellationException e) { + // nothing to do + } + } + return null; + } +} diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/BindingSuggestionProvider.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/BindingSuggestionProvider.java index 3fc4f3e4b5..70e81d3b59 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/BindingSuggestionProvider.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/BindingSuggestionProvider.java @@ -30,13 +30,12 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.commons.progress.ExecutorServiceShutdownWatchable; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.event.BindingConfigChangedEvent; import org.sonarsource.sonarlint.core.event.ConnectionConfigurationAddedEvent; import org.sonarsource.sonarlint.core.repository.config.BindingConfiguration; @@ -73,8 +72,7 @@ public BindingSuggestionProvider(ConfigurationRepository configRepository, Conne this.client = client; this.bindingClueProvider = bindingClueProvider; this.sonarProjectsCache = sonarProjectsCache; - this.executorService = new ExecutorServiceShutdownWatchable<>(new ThreadPoolExecutor(0, 1, 10L, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), r -> new Thread(r, "Binding Suggestion Provider"))); + this.executorService = new ExecutorServiceShutdownWatchable<>(FailSafeExecutors.newSingleThreadExecutor("Binding Suggestion Provider")); } @EventListener @@ -116,7 +114,7 @@ public Map> getBindingSuggestions(String conf private void queueBindingSuggestionComputation(Set configScopeIds, Set candidateConnectionIds) { var cancelMonitor = new SonarLintCancelMonitor(); cancelMonitor.watchForShutdown(executorService); - executorService.submit(() -> { + executorService.execute(() -> { if (enabled.get()) { computeAndNotifyBindingSuggestions(configScopeIds, candidateConnectionIds, cancelMonitor); } else { diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/ConnectionSuggestionProvider.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/ConnectionSuggestionProvider.java index 0253185cbf..6772c93b56 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/ConnectionSuggestionProvider.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/ConnectionSuggestionProvider.java @@ -27,13 +27,11 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.commons.progress.ExecutorServiceShutdownWatchable; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.event.ConfigurationScopesAddedEvent; import org.sonarsource.sonarlint.core.fs.ClientFile; import org.sonarsource.sonarlint.core.fs.ClientFileSystemService; @@ -70,8 +68,7 @@ public ConnectionSuggestionProvider(ConfigurationRepository configRepository, Co this.connectionRepository = connectionRepository; this.client = client; this.bindingClueProvider = bindingClueProvider; - this.executorService = new ExecutorServiceShutdownWatchable<>(new ThreadPoolExecutor(0, 1, 10L, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), r -> new Thread(r, "Connection Suggestion Provider"))); + this.executorService = new ExecutorServiceShutdownWatchable<>(FailSafeExecutors.newSingleThreadExecutor("Connection Suggestion Provider")); this.bindingSuggestionProvider = bindingSuggestionProvider; this.clientFs = clientFs; } @@ -106,7 +103,7 @@ private void queueConnectionSuggestion(Set listConfigScopeIds) { if (!listConfigScopeIds.isEmpty()) { var cancelMonitor = new SonarLintCancelMonitor(); cancelMonitor.watchForShutdown(executorService); - executorService.submit(() -> suggestConnectionForGivenScopes(listConfigScopeIds, cancelMonitor)); + executorService.execute(() -> suggestConnectionForGivenScopes(listConfigScopeIds, cancelMonitor)); } } @@ -114,7 +111,7 @@ private void suggestConnectionForGivenScopes(Set listOfFilesPerConfigSco LOG.debug("Computing connection suggestions"); var connectionSuggestionsByConfigScopeIds = new HashMap>(); var bindingSuggestionsForConfigScopeIds = new HashSet(); - + for (var configScopeId : listOfFilesPerConfigScopeIds) { var effectiveBinding = configRepository.getEffectiveBinding(configScopeId); if (effectiveBinding.isPresent()) { @@ -133,8 +130,8 @@ private void suggestConnectionForGivenScopes(Set listOfFilesPerConfigSco organization -> connectionSuggestionsByConfigScopeIds.computeIfAbsent(configScopeId, s -> new ArrayList<>()) .add(new ConnectionSuggestionDto(new SonarCloudConnectionSuggestionDto(organization, projectKey, ((BindingClueProvider.SonarCloudBindingClue) bindingClue).getRegion()), - bindingClue.isFromSharedConfiguration())) - ), () -> bindingSuggestionsForConfigScopeIds.add(configScopeId)); + bindingClue.isFromSharedConfiguration()))), + () -> bindingSuggestionsForConfigScopeIds.add(configScopeId)); } } } diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/VersionSoonUnsupportedHelper.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/VersionSoonUnsupportedHelper.java index 4ab7dc8142..48735feb11 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/VersionSoonUnsupportedHelper.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/VersionSoonUnsupportedHelper.java @@ -25,14 +25,13 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.sonarsource.sonarlint.core.commons.ConnectionKind; import org.sonarsource.sonarlint.core.commons.Version; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.commons.progress.ExecutorServiceShutdownWatchable; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.event.BindingConfigChangedEvent; import org.sonarsource.sonarlint.core.event.ConfigurationScopesAddedEvent; import org.sonarsource.sonarlint.core.repository.config.ConfigurationRepository; @@ -64,8 +63,7 @@ public VersionSoonUnsupportedHelper(SonarLintRpcClient client, ConfigurationRepo this.connectionRepository = connectionRepository; this.connectionManager = connectionManager; this.synchronizationService = synchronizationService; - this.executorService = new ExecutorServiceShutdownWatchable<>(new ThreadPoolExecutor(0, 1, 10L, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), r -> new Thread(r, "Version Soon Unsupported Helper"))); + this.executorService = new ExecutorServiceShutdownWatchable<>(FailSafeExecutors.newSingleThreadExecutor("Version Soon Unsupported Helper")); } @EventListener @@ -99,7 +97,7 @@ private void checkIfSoonUnsupportedOncePerConnection(Set configScopeIds) private void queueCheckIfSoonUnsupported(String connectionId, String configScopeId) { var cancelMonitor = new SonarLintCancelMonitor(); cancelMonitor.watchForShutdown(executorService); - executorService.submit(() -> { + executorService.execute(() -> { try { var connection = connectionRepository.getConnectionById(connectionId); if (connection != null && connection.getKind() == ConnectionKind.SONARQUBE) { diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/analysis/AnalysisService.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/analysis/AnalysisService.java index b6a5274006..8008ce9e80 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/analysis/AnalysisService.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/analysis/AnalysisService.java @@ -38,8 +38,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -67,6 +66,7 @@ import org.sonarsource.sonarlint.core.commons.monitoring.MonitoringService; import org.sonarsource.sonarlint.core.commons.progress.ProgressMonitor; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.event.BindingConfigChangedEvent; import org.sonarsource.sonarlint.core.event.ConfigurationScopeRemovedEvent; import org.sonarsource.sonarlint.core.event.ConfigurationScopesAddedEvent; @@ -156,7 +156,7 @@ public class AnalysisService { private final MonitoringService monitoringService; private boolean automaticAnalysisEnabled; private final Path esLintBridgeServerPath; - private final ScheduledExecutorService scheduledAnalysisExecutor = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "SonarLint Analysis Executor")); + private final ExecutorService scheduledAnalysisExecutor = FailSafeExecutors.newSingleThreadExecutor("SonarLint Analysis Executor"); public AnalysisService(SonarLintRpcClient client, ConfigurationRepository configurationRepository, LanguageSupportRepository languageSupportRepository, StorageService storageService, PluginsService pluginsService, RulesService rulesService, RulesRepository rulesRepository, @@ -894,17 +894,15 @@ private void triggerAnalysisForOpenFiles() { private UUID triggerForcedAnalysis(String configurationScopeId, List files, boolean hotspotsOnly) { if (isReadyForAnalysis(configurationScopeId)) { var analysisId = UUID.randomUUID(); - scheduledAnalysisExecutor.submit(() -> { - analyze(new SonarLintCancelMonitor(), configurationScopeId, analysisId, files, Map.of(), System.currentTimeMillis(), true, hotspotsOnly); - return analysisId; - }); + scheduledAnalysisExecutor + .execute(() -> analyze(new SonarLintCancelMonitor(), configurationScopeId, analysisId, files, Map.of(), System.currentTimeMillis(), true, hotspotsOnly)); } LOG.debug("Skipping analysis for configuration scope {}. Not ready for analysis", configurationScopeId); return null; } private void triggerAnalysis(String configurationScopeId, List files) { - scheduledAnalysisExecutor.submit(() -> { + scheduledAnalysisExecutor.execute(() -> { if (shouldTriggerAutomaticAnalysis(configurationScopeId)) { List filteredFiles = fileExclusionService.filterOutClientExcludedFiles(configurationScopeId, files); analyze(new SonarLintCancelMonitor(), configurationScopeId, UUID.randomUUID(), filteredFiles, Map.of(), System.currentTimeMillis(), true, false); diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/commons/SmartCancelableLoadingCache.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/commons/SmartCancelableLoadingCache.java index e62104d57f..f2d00b79a8 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/commons/SmartCancelableLoadingCache.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/commons/SmartCancelableLoadingCache.java @@ -23,13 +23,13 @@ import java.util.Objects; import java.util.concurrent.CancellationException; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import javax.annotation.Nullable; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.commons.progress.ExecutorServiceShutdownWatchable; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; /** * A cache with async computation of values, and supporting cancellation. @@ -58,7 +58,7 @@ public SmartCancelableLoadingCache(String threadName, BiFunction valueComputer, @Nullable Listener listener) { - this.executorService = new ExecutorServiceShutdownWatchable<>(Executors.newSingleThreadExecutor(r -> new Thread(r, threadName))); + this.executorService = new ExecutorServiceShutdownWatchable<>(FailSafeExecutors.newSingleThreadExecutor(threadName)); this.threadName = threadName; this.valueComputer = valueComputer; this.listener = listener; diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/embedded/server/RequestHandlerBindingAssistant.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/embedded/server/RequestHandlerBindingAssistant.java index 90d8f072c8..797af68140 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/embedded/server/RequestHandlerBindingAssistant.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/embedded/server/RequestHandlerBindingAssistant.java @@ -25,8 +25,6 @@ import java.util.HashSet; import java.util.Objects; import java.util.concurrent.CancellationException; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import javax.annotation.CheckForNull; @@ -39,6 +37,7 @@ import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.commons.progress.ExecutorServiceShutdownWatchable; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.repository.config.ConfigurationRepository; import org.sonarsource.sonarlint.core.repository.connection.ConnectionConfigurationRepository; import org.sonarsource.sonarlint.core.rpc.protocol.SonarLintRpcClient; @@ -73,8 +72,7 @@ public RequestHandlerBindingAssistant(BindingSuggestionProvider bindingSuggestio this.connectionConfigurationRepository = connectionConfigurationRepository; this.configurationRepository = configurationRepository; this.userTokenService = userTokenService; - this.executorService = new ExecutorServiceShutdownWatchable<>(new ThreadPoolExecutor(0, 1, 10L, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), r -> new Thread(r, "Show Issue or Hotspot Request Handler"))); + this.executorService = new ExecutorServiceShutdownWatchable<>(FailSafeExecutors.newSingleThreadExecutor("Show Issue or Hotspot Request Handler")); this.sonarCloudActiveEnvironment = sonarCloudActiveEnvironment; this.repository = repository; } @@ -86,7 +84,7 @@ interface Callback { void assistConnectionAndBindingIfNeededAsync(AssistCreatingConnectionParams connectionParams, String projectKey, String origin, Callback callback) { var cancelMonitor = new SonarLintCancelMonitor(); cancelMonitor.watchForShutdown(executorService); - executorService.submit(() -> assistConnectionAndBindingIfNeeded(connectionParams, projectKey, origin, callback, cancelMonitor)); + executorService.execute(() -> assistConnectionAndBindingIfNeeded(connectionParams, projectKey, origin, callback, cancelMonitor)); } private void assistConnectionAndBindingIfNeeded(AssistCreatingConnectionParams connectionParams, String projectKey, String origin, @@ -95,9 +93,8 @@ private void assistConnectionAndBindingIfNeeded(AssistCreatingConnectionParams c LOG.debug("Assist connection and binding if needed for project {} and server {}", projectKey, serverUrl); try { var isSonarCloud = connectionParams.getConnectionParams().isRight(); - var connectionsMatchingOrigin = isSonarCloud ? - connectionConfigurationRepository.findByOrganization(connectionParams.getConnectionParams().getRight().getOrganizationKey()) : - connectionConfigurationRepository.findByUrl(serverUrl); + var connectionsMatchingOrigin = isSonarCloud ? connectionConfigurationRepository.findByOrganization(connectionParams.getConnectionParams().getRight().getOrganizationKey()) + : connectionConfigurationRepository.findByUrl(serverUrl); if (connectionsMatchingOrigin.isEmpty()) { startFullBindingProcess(); try { @@ -130,8 +127,8 @@ private void assistConnectionAndBindingIfNeeded(AssistCreatingConnectionParams c } private String getServerUrl(AssistCreatingConnectionParams connectionParams) { - return connectionParams.getConnectionParams().isLeft() ? connectionParams.getConnectionParams().getLeft().getServerUrl() : - sonarCloudActiveEnvironment.getUri(SonarCloudRegion.valueOf(connectionParams.getConnectionParams().getRight().getRegion().name())).toString(); + return connectionParams.getConnectionParams().isLeft() ? connectionParams.getConnectionParams().getLeft().getServerUrl() + : sonarCloudActiveEnvironment.getUri(SonarCloudRegion.valueOf(connectionParams.getConnectionParams().getRight().getRegion().name())).toString(); } private AssistCreatingConnectionResponse assistCreatingConnectionAndWaitForRepositoryUpdate( @@ -248,7 +245,6 @@ NewBinding assistBinding(String connectionId, boolean isSonarCloud, String proje return new NewBinding(connectionId, response.getConfigurationScopeId()); } - static class NewBinding { private final String connectionId; private final String configurationScopeId; diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/server/event/ServerEventsService.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/server/event/ServerEventsService.java index 4d7046662f..c02de5d7b7 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/server/event/ServerEventsService.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/server/event/ServerEventsService.java @@ -20,19 +20,19 @@ package org.sonarsource.sonarlint.core.server.event; import com.google.common.util.concurrent.MoreExecutors; +import jakarta.annotation.PreDestroy; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import jakarta.annotation.PreDestroy; import org.sonarsource.sonarlint.core.ConnectionManager; import org.sonarsource.sonarlint.core.commons.Binding; import org.sonarsource.sonarlint.core.commons.ConnectionKind; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.event.BindingConfigChangedEvent; import org.sonarsource.sonarlint.core.event.ConfigurationScopeRemovedEvent; @@ -63,7 +63,7 @@ public class ServerEventsService { private final boolean shouldManageServerSentEvents; private final ApplicationEventPublisher eventPublisher; private final Map streamsPerConnectionId = new ConcurrentHashMap<>(); - private final ExecutorService executorService = Executors.newSingleThreadExecutor(r -> new Thread(r, "sonarlint-server-sent-events-subscriber")); + private final ExecutorService executorService = FailSafeExecutors.newSingleThreadExecutor("sonarlint-server-sent-events-subscriber"); public ServerEventsService(ConfigurationRepository configurationRepository, ConnectionConfigurationRepository connectionConfigurationRepository, ConnectionManager connectionManager, LanguageSupportRepository languageSupportRepository, InitializeParams initializeParams, ApplicationEventPublisher eventPublisher) { @@ -80,7 +80,7 @@ public void handle(ConfigurationScopesAddedEvent event) { if (!shouldManageServerSentEvents) { return; } - executorService.submit(() -> subscribeAll(event.getAddedConfigurationScopeIds())); + executorService.execute(() -> subscribeAll(event.getAddedConfigurationScopeIds())); } @EventListener @@ -94,7 +94,7 @@ public void handle(ConfigurationScopeRemovedEvent event) { if (bindingConfigurationFromRepository == null || isBindingDifferent(removedBindingConfiguration, bindingConfigurationFromRepository)) { // it has not been re-added in the meantime, or re-added with different binding - executorService.submit(() -> unsubscribe(removedBindingConfiguration)); + executorService.execute(() -> unsubscribe(removedBindingConfiguration)); } } @@ -105,7 +105,7 @@ public void handle(BindingConfigChangedEvent event) { } var previousBinding = event.getPreviousConfig(); if (isBindingDifferent(previousBinding, event.getNewConfig())) { - executorService.submit(() -> { + executorService.execute(() -> { unsubscribe(previousBinding); subscribe(event.getConfigScopeId()); }); @@ -119,7 +119,7 @@ public void handle(ConnectionConfigurationAddedEvent event) { } // This is only to handle the case where binding was invalid (connection did not exist) and became valid (matching connection was created) var connectionId = event.getAddedConnectionId(); - executorService.submit(() -> subscribe(connectionId, configurationRepository.getSonarProjectsUsedForConnection(connectionId))); + executorService.execute(() -> subscribe(connectionId, configurationRepository.getSonarProjectsUsedForConnection(connectionId))); } @EventListener @@ -127,7 +127,7 @@ public void handle(ConnectionConfigurationRemovedEvent event) { if (!shouldManageServerSentEvents) { return; } - executorService.submit(() -> { + executorService.execute(() -> { var stream = streamsPerConnectionId.remove(event.getRemovedConnectionId()); if (stream != null) { stream.stop(); @@ -141,7 +141,7 @@ public void handle(ConnectionConfigurationUpdatedEvent event) { return; } // URL might have changed, in doubt resubscribe - executorService.submit(() -> resubscribe(event.getUpdatedConnectionId())); + executorService.execute(() -> resubscribe(event.getUpdatedConnectionId())); } @EventListener @@ -149,7 +149,7 @@ public void handle(ConnectionCredentialsChangedEvent event) { if (!shouldManageServerSentEvents) { return; } - executorService.submit(() -> resubscribe(event.getConnectionId())); + executorService.execute(() -> resubscribe(event.getConnectionId())); } private static boolean isBindingDifferent(BindingConfiguration previousConfig, BindingConfiguration newConfig) { diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/smartnotifications/SmartNotifications.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/smartnotifications/SmartNotifications.java index 611d3ad6ec..725e955936 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/smartnotifications/SmartNotifications.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/smartnotifications/SmartNotifications.java @@ -27,7 +27,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -38,6 +37,7 @@ import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.commons.progress.ExecutorServiceShutdownWatchable; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.event.SonarServerEventReceivedEvent; import org.sonarsource.sonarlint.core.repository.config.ConfigurationRepository; import org.sonarsource.sonarlint.core.repository.connection.AbstractConnectionConfiguration; @@ -86,7 +86,7 @@ public void initialize() { if (!params.getFeatureFlags().shouldManageSmartNotifications()) { return; } - smartNotificationsPolling = new ExecutorServiceShutdownWatchable<>(Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "Smart Notifications Polling"))); + smartNotificationsPolling = new ExecutorServiceShutdownWatchable<>(FailSafeExecutors.newSingleThreadScheduledExecutor("Smart Notifications Polling")); var cancelMonitor = new SonarLintCancelMonitor(); cancelMonitor.watchForShutdown(smartNotificationsPolling); smartNotificationsPolling.getWrapped().scheduleAtFixedRate(() -> this.poll(cancelMonitor), 1, 60, TimeUnit.SECONDS); diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/sync/FindingsSynchronizationService.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/sync/FindingsSynchronizationService.java index 45b1a596ac..381a252056 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/sync/FindingsSynchronizationService.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/sync/FindingsSynchronizationService.java @@ -24,11 +24,11 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.stream.Collectors; import org.sonarsource.sonarlint.core.branch.SonarProjectBranchTrackingService; import org.sonarsource.sonarlint.core.commons.Binding; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.file.FilePathTranslation; import org.sonarsource.sonarlint.core.file.PathTranslationService; import org.sonarsource.sonarlint.core.repository.config.ConfigurationRepository; @@ -49,7 +49,7 @@ public FindingsSynchronizationService(ConfigurationRepository configurationRepos this.pathTranslationService = pathTranslationService; this.issueSynchronizationService = issueSynchronizationService; this.hotspotSynchronizationService = hotspotSynchronizationService; - this.issueUpdaterExecutorService = Executors.newSingleThreadExecutor(r -> new Thread(r, "sonarlint-server-tracking-issue-updater")); + this.issueUpdaterExecutorService = FailSafeExecutors.newSingleThreadExecutor("sonarlint-server-tracking-issue-updater"); } public void refreshServerFindings(String configurationScopeId, Set pathsToRefresh) { diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/sync/SynchronizationService.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/sync/SynchronizationService.java index c4e8be1bd5..0ea2c91dca 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/sync/SynchronizationService.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/sync/SynchronizationService.java @@ -33,7 +33,6 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -47,6 +46,7 @@ import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.commons.progress.ExecutorServiceShutdownWatchable; import org.sonarsource.sonarlint.core.commons.progress.SonarLintCancelMonitor; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.event.BindingConfigChangedEvent; import org.sonarsource.sonarlint.core.event.ConfigurationScopeRemovedEvent; import org.sonarsource.sonarlint.core.event.ConfigurationScopesAddedEvent; @@ -98,7 +98,7 @@ public class SynchronizationService { private final PluginsRepository pluginsRepository; private final ApplicationEventPublisher applicationEventPublisher; private final ExecutorServiceShutdownWatchable scheduledSynchronizer = new ExecutorServiceShutdownWatchable<>( - Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "SonarLint Local Storage Synchronizer"))); + FailSafeExecutors.newSingleThreadScheduledExecutor("SonarLint Local Storage Synchronizer")); private final Set ignoreBranchEventForScopes = ConcurrentHashMap.newKeySet(); public SynchronizationService(SonarLintRpcClient client, ConfigurationRepository configurationRepository, LanguageSupportRepository languageSupportRepository, @@ -148,7 +148,7 @@ private void safeSyncAllConfigScopes(SonarLintCancelMonitor cancelMonitor) { private void synchronizeProjectsAsync(Map>> boundScopeByConnectionAndSonarProject) { var cancelMonitor = new SonarLintCancelMonitor(); cancelMonitor.watchForShutdown(scheduledSynchronizer); - scheduledSynchronizer.submit(() -> synchronizeProjectsSync(boundScopeByConnectionAndSonarProject, cancelMonitor)); + scheduledSynchronizer.execute(() -> synchronizeProjectsSync(boundScopeByConnectionAndSonarProject, cancelMonitor)); } private void synchronizeProjectsSync(Map>> boundScopeByConnectionAndSonarProject, SonarLintCancelMonitor cancelMonitor) { @@ -290,8 +290,8 @@ public void onConnectionCredentialsChanged(ConnectionCredentialsChangedEvent eve private void synchronizeConnectionAndProjectsIfNeededAsync(String connectionId, Collection boundScopes) { var cancelMonitor = new SonarLintCancelMonitor(); cancelMonitor.watchForShutdown(scheduledSynchronizer); - scheduledSynchronizer.submit(() -> connectionManager.withValidConnection(connectionId, serverApi -> - synchronizeConnectionAndProjectsIfNeededSync(connectionId, serverApi, boundScopes, cancelMonitor))); + scheduledSynchronizer.execute( + () -> connectionManager.withValidConnection(connectionId, serverApi -> synchronizeConnectionAndProjectsIfNeededSync(connectionId, serverApi, boundScopes, cancelMonitor))); } private void synchronizeConnectionAndProjectsIfNeededSync(String connectionId, ServerApi serverApi, Collection boundScopes, SonarLintCancelMonitor cancelMonitor) { diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/telemetry/TelemetryService.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/telemetry/TelemetryService.java index 377fd8d963..9bb46b1b7d 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/telemetry/TelemetryService.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/telemetry/TelemetryService.java @@ -23,7 +23,6 @@ import jakarta.annotation.PreDestroy; import java.util.Objects; import java.util.Set; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -31,6 +30,7 @@ import org.sonarsource.sonarlint.core.analysis.AnalysisFinishedEvent; import org.sonarsource.sonarlint.core.commons.api.SonarLanguage; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.event.LocalOnlyIssueStatusChangedEvent; import org.sonarsource.sonarlint.core.event.ServerIssueStatusChangedEvent; import org.sonarsource.sonarlint.core.rpc.protocol.SonarLintRpcClient; @@ -62,7 +62,7 @@ public TelemetryService(InitializeParams initializeParams, SonarLintRpcClient so this.client = sonarlintClient; this.telemetryServerAttributesProvider = telemetryServerAttributesProvider; this.telemetryManager = telemetryManager; - this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "SonarLint Telemetry")); + this.scheduledExecutor = FailSafeExecutors.newSingleThreadScheduledExecutor("SonarLint Telemetry"); initTelemetryAndScheduleUpload(initializeParams); } diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/tracking/streaming/Alarm.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/tracking/streaming/Alarm.java index 2c66e6926b..61747dd6eb 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/tracking/streaming/Alarm.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/tracking/streaming/Alarm.java @@ -20,10 +20,10 @@ package org.sonarsource.sonarlint.core.tracking.streaming; import java.time.Duration; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; public class Alarm { private final Duration duration; @@ -34,7 +34,7 @@ public class Alarm { public Alarm(String name, Duration duration, Runnable endRunnable) { this.duration = duration; this.endRunnable = endRunnable; - executorService = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, name)); + this.executorService = FailSafeExecutors.newSingleThreadScheduledExecutor(name); } public void schedule() { diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/websocket/SonarCloudWebSocket.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/websocket/SonarCloudWebSocket.java index 0176546dcc..13b6f93af8 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/websocket/SonarCloudWebSocket.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/websocket/SonarCloudWebSocket.java @@ -31,7 +31,6 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -41,6 +40,7 @@ import java.util.stream.Stream; import org.sonarsource.sonarlint.core.commons.log.LogOutput; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.http.WebSocketClient; import org.sonarsource.sonarlint.core.serverapi.push.SonarServerEvent; import org.sonarsource.sonarlint.core.serverapi.push.parsing.EventParser; @@ -74,7 +74,7 @@ public class SonarCloudWebSocket { private static final Gson gson = new Gson(); private CompletableFuture wsFuture; private final History history = new History(); - private final ScheduledExecutorService sonarCloudWebSocketScheduler = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "sonarcloud-websocket-scheduled-jobs")); + private final ScheduledExecutorService sonarCloudWebSocketScheduler = FailSafeExecutors.newSingleThreadScheduledExecutor("sonarcloud-websocket-scheduled-jobs"); private final AtomicBoolean closingInitiated = new AtomicBoolean(false); private final CompletableFuture webSocketInputClosed = new CompletableFuture<>(); diff --git a/backend/core/src/main/java/org/sonarsource/sonarlint/core/websocket/WebSocketService.java b/backend/core/src/main/java/org/sonarsource/sonarlint/core/websocket/WebSocketService.java index 096c02ccc9..adead130d7 100644 --- a/backend/core/src/main/java/org/sonarsource/sonarlint/core/websocket/WebSocketService.java +++ b/backend/core/src/main/java/org/sonarsource/sonarlint/core/websocket/WebSocketService.java @@ -26,7 +26,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import javax.annotation.CheckForNull; @@ -34,6 +33,7 @@ import org.sonarsource.sonarlint.core.commons.Binding; import org.sonarsource.sonarlint.core.commons.BoundScope; import org.sonarsource.sonarlint.core.commons.ConnectionKind; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; import org.sonarsource.sonarlint.core.event.BindingConfigChangedEvent; import org.sonarsource.sonarlint.core.event.ConfigurationScopeRemovedEvent; @@ -64,9 +64,9 @@ public class WebSocketService { private final ConnectionAwareHttpClientProvider connectionAwareHttpClientProvider; private final ApplicationEventPublisher eventPublisher; protected SonarCloudWebSocket sonarCloudWebSocket; - private SonarCloudActiveEnvironment sonarCloudActiveEnvironment; + private final SonarCloudActiveEnvironment sonarCloudActiveEnvironment; private String connectionIdUsedToCreateConnection; - private final ExecutorService executorService = Executors.newSingleThreadExecutor(r -> new Thread(r, "sonarlint-websocket-subscriber")); + private final ExecutorService executorService = FailSafeExecutors.newSingleThreadExecutor("sonarlint-websocket-subscriber"); public WebSocketService(ConnectionConfigurationRepository connectionConfigurationRepository, ConfigurationRepository configurationRepository, ConnectionAwareHttpClientProvider connectionAwareHttpClientProvider, InitializeParams params, SonarCloudActiveEnvironment sonarCloudActiveEnvironment, @@ -80,7 +80,7 @@ public WebSocketService(ConnectionConfigurationRepository connectionConfiguratio } protected void reopenConnectionOnClose() { - executorService.submit(() -> { + executorService.execute(() -> { var connectionId = connectionIdsInterestedInNotifications.stream().findFirst().orElse(null); if (this.sonarCloudWebSocket != null && connectionId != null) { // If connection already exists, close it and create new one before it expires on its own @@ -94,7 +94,7 @@ public void handleEvent(BindingConfigChangedEvent bindingConfigChangedEvent) { if (!shouldEnableWebSockets) { return; } - executorService.submit(() -> considerScope(bindingConfigChangedEvent.getConfigScopeId())); + executorService.execute(() -> considerScope(bindingConfigChangedEvent.getConfigScopeId())); } @EventListener @@ -102,7 +102,7 @@ public void handleEvent(ConfigurationScopesAddedEvent configurationScopesAddedEv if (!shouldEnableWebSockets) { return; } - executorService.submit(() -> considerAllBoundConfigurationScopes(configurationScopesAddedEvent.getAddedConfigurationScopeIds())); + executorService.execute(() -> considerAllBoundConfigurationScopes(configurationScopesAddedEvent.getAddedConfigurationScopeIds())); } @EventListener @@ -111,7 +111,7 @@ public void handleEvent(ConfigurationScopeRemovedEvent configurationScopeRemoved return; } var removedConfigurationScopeId = configurationScopeRemovedEvent.getRemovedConfigurationScopeId(); - executorService.submit(() -> { + executorService.execute(() -> { forget(removedConfigurationScopeId); closeSocketIfNoMoreNeeded(); }); @@ -123,7 +123,7 @@ public void handleEvent(ConnectionConfigurationAddedEvent connectionConfiguratio return; } // This is only to handle the case where binding was invalid (connection did not exist) and became valid (matching connection was created) - executorService.submit(() -> considerConnection(connectionConfigurationAddedEvent.getAddedConnectionId())); + executorService.execute(() -> considerConnection(connectionConfigurationAddedEvent.getAddedConnectionId())); } @EventListener @@ -132,7 +132,7 @@ public void handleEvent(ConnectionConfigurationUpdatedEvent connectionConfigurat return; } var updatedConnectionId = connectionConfigurationUpdatedEvent.getUpdatedConnectionId(); - executorService.submit(() -> { + executorService.execute(() -> { if (didDisableNotifications(updatedConnectionId)) { forgetConnection(updatedConnectionId, "Notifications were disabled"); } else if (didEnableNotifications(updatedConnectionId)) { @@ -147,7 +147,7 @@ public void handleEvent(ConnectionConfigurationRemovedEvent connectionConfigurat return; } String removedConnectionId = connectionConfigurationRemovedEvent.getRemovedConnectionId(); - executorService.submit(() -> forgetConnection(removedConnectionId, "Connection was removed")); + executorService.execute(() -> forgetConnection(removedConnectionId, "Connection was removed")); } @EventListener @@ -156,7 +156,7 @@ public void handleEvent(ConnectionCredentialsChangedEvent connectionCredentialsC return; } var connectionId = connectionCredentialsChangedEvent.getConnectionId(); - executorService.submit(() -> { + executorService.execute(() -> { if (isEligibleConnection(connectionId) && connectionIdsInterestedInNotifications.contains(connectionId)) { reopenConnection(connectionId, "Credentials have changed"); } diff --git a/backend/http/src/main/java/org/sonarsource/sonarlint/core/http/HttpClientProvider.java b/backend/http/src/main/java/org/sonarsource/sonarlint/core/http/HttpClientProvider.java index 5baf7098c3..fa1aca3218 100644 --- a/backend/http/src/main/java/org/sonarsource/sonarlint/core/http/HttpClientProvider.java +++ b/backend/http/src/main/java/org/sonarsource/sonarlint/core/http/HttpClientProvider.java @@ -20,15 +20,14 @@ package org.sonarsource.sonarlint.core.http; import com.google.common.util.concurrent.MoreExecutors; +import jakarta.annotation.PreDestroy; import java.net.ProxySelector; import java.nio.file.Files; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import javax.annotation.Nullable; import javax.net.ssl.SSLContext; -import jakarta.annotation.PreDestroy; import nl.altindag.ssl.SSLFactory; import nl.altindag.ssl.model.TrustManagerParameters; import org.apache.commons.lang3.SystemUtils; @@ -46,6 +45,7 @@ import org.apache.hc.core5.io.CloseMode; import org.apache.hc.core5.util.Timeout; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.http.ssl.SslConfig; import static org.sonarsource.sonarlint.core.http.ThreadFactories.threadWithNamePrefix; @@ -68,7 +68,7 @@ public static HttpClientProvider forTesting() { public HttpClientProvider(String userAgent, HttpConfig httpConfig, @Nullable Predicate trustManagerParametersPredicate, ProxySelector proxySelector, CredentialsProvider proxyCredentialsProvider) { this.userAgent = userAgent; - this.webSocketThreadPool = Executors.newCachedThreadPool(threadWithNamePrefix("sonarcloud-websocket-")); + this.webSocketThreadPool = FailSafeExecutors.newCachedThreadPool(threadWithNamePrefix("sonarcloud-websocket-")); var asyncConnectionManager = PoolingAsyncClientConnectionManagerBuilder.create() .setTlsStrategy(new DefaultClientTlsStrategy(configureSsl(httpConfig.getSslConfig(), trustManagerParametersPredicate))) .setDefaultTlsConfig(TlsConfig.custom() diff --git a/backend/server-api/src/main/java/org/sonarsource/sonarlint/core/serverapi/stream/EventStream.java b/backend/server-api/src/main/java/org/sonarsource/sonarlint/core/serverapi/stream/EventStream.java index e38cdf0868..b8994cc3f4 100644 --- a/backend/server-api/src/main/java/org/sonarsource/sonarlint/core/serverapi/stream/EventStream.java +++ b/backend/server-api/src/main/java/org/sonarsource/sonarlint/core/serverapi/stream/EventStream.java @@ -20,7 +20,6 @@ package org.sonarsource.sonarlint.core.serverapi.stream; import com.google.common.util.concurrent.MoreExecutors; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -28,6 +27,7 @@ import java.util.function.Consumer; import javax.annotation.Nullable; import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger; +import org.sonarsource.sonarlint.core.commons.util.FailSafeExecutors; import org.sonarsource.sonarlint.core.http.HttpClient; import org.sonarsource.sonarlint.core.http.HttpConnectionListener; import org.sonarsource.sonarlint.core.serverapi.ServerApiHelper; @@ -49,7 +49,7 @@ public class EventStream { private final Consumer eventConsumer; public EventStream(ServerApiHelper helper, Consumer eventConsumer) { - this(helper, eventConsumer, Executors.newScheduledThreadPool(1)); + this(helper, eventConsumer, FailSafeExecutors.newSingleThreadScheduledExecutor("sonarlint-event-stream-consumer")); } EventStream(ServerApiHelper helper, Consumer eventConsumer, ScheduledExecutorService executor) { diff --git a/rpc-protocol/src/main/java/org/sonarsource/sonarlint/core/rpc/protocol/SingleThreadedMessageConsumer.java b/rpc-protocol/src/main/java/org/sonarsource/sonarlint/core/rpc/protocol/SingleThreadedMessageConsumer.java index 07d59ed76a..20de66293b 100644 --- a/rpc-protocol/src/main/java/org/sonarsource/sonarlint/core/rpc/protocol/SingleThreadedMessageConsumer.java +++ b/rpc-protocol/src/main/java/org/sonarsource/sonarlint/core/rpc/protocol/SingleThreadedMessageConsumer.java @@ -36,7 +36,7 @@ public class SingleThreadedMessageConsumer implements MessageConsumer { private final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); public SingleThreadedMessageConsumer(MessageConsumer syncMessageConsumer, ExecutorService threadPool, Consumer errorLogger) { - threadPool.submit(() -> { + threadPool.execute(() -> { while (true) { Message message; try {