From 1393eb6077f5691693a3dcb62ee758f8b332268a Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 15 Mar 2024 16:08:54 +0700 Subject: [PATCH 1/8] If the tor process cannot be terminated we had a 2 minutes wait period before we threw an exception. The shutdown timeout was not triggered as the tor shutdown code was not in a CompleteableFuture. This change reduce the tor process exit wait time to 5 seconds. This seems to be sufficient for any normal shutdown. The overall timeout for the shutdown is 10 seconds, so we don't want to let one shutdown process consume too much of it. Added more logs as well. --- .../src/main/java/bisq/network/p2p/ServiceNode.java | 3 --- .../network/p2p/node/transport/TorTransportService.java | 3 +-- network/tor/tor/src/main/java/bisq/tor/TorService.java | 9 ++++++--- .../java/bisq/tor/controller/NativeTorController.java | 1 + .../src/main/java/bisq/tor/process/NativeTorProcess.java | 7 +++++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/network/network/src/main/java/bisq/network/p2p/ServiceNode.java b/network/network/src/main/java/bisq/network/p2p/ServiceNode.java index 4ce07a09e8..0a01cca3cb 100644 --- a/network/network/src/main/java/bisq/network/p2p/ServiceNode.java +++ b/network/network/src/main/java/bisq/network/p2p/ServiceNode.java @@ -55,7 +55,6 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.TimeUnit; import static com.google.common.base.Preconditions.checkArgument; import static java.util.concurrent.CompletableFuture.runAsync; @@ -245,8 +244,6 @@ CompletableFuture shutdown() { inventoryService.ifPresent(InventoryService::shutdown); confidentialMessageService.ifPresent(ConfidentialMessageService::shutdown); return nodesById.shutdown() - .orTimeout(10, TimeUnit.SECONDS) - .handle((result, throwable) -> throwable == null && result) .thenCompose(result -> transportService.shutdown()) .whenComplete((result, throwable) -> setState(State.TERMINATED)); } diff --git a/network/network/src/main/java/bisq/network/p2p/node/transport/TorTransportService.java b/network/network/src/main/java/bisq/network/p2p/node/transport/TorTransportService.java index 71628a3239..1a91c7b1aa 100644 --- a/network/network/src/main/java/bisq/network/p2p/node/transport/TorTransportService.java +++ b/network/network/src/main/java/bisq/network/p2p/node/transport/TorTransportService.java @@ -70,8 +70,7 @@ public CompletableFuture shutdown() { startBootstrapProgressUpdater.stop(); startBootstrapProgressUpdater = null; } - torService.shutdown().join(); - return CompletableFuture.completedFuture(true); + return torService.shutdown(); } @Override diff --git a/network/tor/tor/src/main/java/bisq/tor/TorService.java b/network/tor/tor/src/main/java/bisq/tor/TorService.java index 6cc4087832..bc8a17c26b 100644 --- a/network/tor/tor/src/main/java/bisq/tor/TorService.java +++ b/network/tor/tor/src/main/java/bisq/tor/TorService.java @@ -106,9 +106,12 @@ public CompletableFuture initialize() { @Override public CompletableFuture shutdown() { - nativeTorController.shutdown(); - torProcess.ifPresent(NativeTorProcess::waitUntilExited); - return CompletableFuture.completedFuture(true); + log.info("shutdown"); + return CompletableFuture.supplyAsync(() -> { + nativeTorController.shutdown(); + torProcess.ifPresent(NativeTorProcess::waitUntilExited); + return true; + }); } public Observable getBootstrapEvent() { diff --git a/network/tor/tor/src/main/java/bisq/tor/controller/NativeTorController.java b/network/tor/tor/src/main/java/bisq/tor/controller/NativeTorController.java index 8e9a037085..41a7792e1d 100644 --- a/network/tor/tor/src/main/java/bisq/tor/controller/NativeTorController.java +++ b/network/tor/tor/src/main/java/bisq/tor/controller/NativeTorController.java @@ -151,6 +151,7 @@ public void waitUntilBootstrapped() { } public void shutdown() { + log.info("Send SHUTDOWN signal to tor control"); boolean canShutdown = isRunning.compareAndSet(true, false); if (!canShutdown) { return; diff --git a/network/tor/tor/src/main/java/bisq/tor/process/NativeTorProcess.java b/network/tor/tor/src/main/java/bisq/tor/process/NativeTorProcess.java index b1a61e96d3..86d2646381 100644 --- a/network/tor/tor/src/main/java/bisq/tor/process/NativeTorProcess.java +++ b/network/tor/tor/src/main/java/bisq/tor/process/NativeTorProcess.java @@ -92,11 +92,14 @@ public void waitUntilControlPortReady() { } public void waitUntilExited() { + log.info("Wait until tor process has exited"); process.ifPresent(process -> { try { - boolean isSuccess = process.waitFor(2, TimeUnit.MINUTES); + boolean isSuccess = process.waitFor(5, TimeUnit.SECONDS); if (!isSuccess) { - throw new CouldNotWaitForTorShutdownException("Tor still running after 2 minutes timeout."); + throw new CouldNotWaitForTorShutdownException("Tor process has not exited after 5 seconds."); + } else { + log.info("Tor process has exited successfully"); } } catch (InterruptedException e) { throw new CouldNotWaitForTorShutdownException(e); From 81add69db9668ae7bfe3d5cc95970d62241d74a1 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 15 Mar 2024 17:56:14 +0700 Subject: [PATCH 2/8] Add popups in case at startup or shutdown an error occurred. --- .../java/bisq/application/Executable.java | 7 ++ .../DesktopApplicationService.java | 20 ++++-- .../bisq/desktop_app/DesktopExecutable.java | 66 ++++++++++++++++++- .../src/main/resources/application.properties | 4 ++ 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/bisq/application/Executable.java b/application/src/main/java/bisq/application/Executable.java index 16b0147914..8c4b01779d 100644 --- a/application/src/main/java/bisq/application/Executable.java +++ b/application/src/main/java/bisq/application/Executable.java @@ -37,15 +37,22 @@ public void shutdown() { return; } shutDownStarted = true; + notifyAboutShutdown(); if (applicationService != null) { applicationService.shutdown() .thenRun(() -> { shutDownHandlers.forEach(Runnable::run); exitJvm(); }); + } else { + shutDownHandlers.forEach(Runnable::run); + exitJvm(); } } + protected void notifyAboutShutdown() { + } + protected void exitJvm() { log.info("Exiting JVM"); System.exit(OsUtils.EXIT_SUCCESS); diff --git a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopApplicationService.java b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopApplicationService.java index 2ce327a422..d524997a47 100644 --- a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopApplicationService.java +++ b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopApplicationService.java @@ -26,6 +26,7 @@ import bisq.common.application.Service; import bisq.common.observable.Observable; import bisq.common.util.CompletableFutureUtils; +import bisq.common.util.ExceptionUtil; import bisq.contract.ContractService; import bisq.desktop.ServiceProvider; import bisq.desktop.State; @@ -63,10 +64,17 @@ @Slf4j public class DesktopApplicationService extends ApplicationService { + public static final long STARTUP_TIMEOUT_SEC = 300; + public static final long SHUTDOWN_TIMEOUT_SEC = 10; + @Getter private final ServiceProvider serviceProvider; @Getter private final Observable state = new Observable<>(State.INITIALIZE_APP); + @Getter + private final Observable shutDownErrorMessage = new Observable<>(); + @Getter + private final Observable startupErrorMessage = new Observable<>(); private final SecurityService securityService; private final Optional walletService; @@ -235,7 +243,7 @@ public CompletableFuture initialize() { .thenCompose(result -> tradeService.initialize()) .thenCompose(result -> updaterService.initialize()) .thenCompose(result -> bisqEasyService.initialize()) - .orTimeout(5, TimeUnit.MINUTES) + .orTimeout(STARTUP_TIMEOUT_SEC, TimeUnit.SECONDS) .handle((result, throwable) -> { if (throwable == null) { if (result != null && result) { @@ -243,10 +251,12 @@ public CompletableFuture initialize() { log.info("ApplicationService initialized"); return true; } else { - log.error("Initializing applicationService failed"); + startupErrorMessage.set("Initializing applicationService failed with result=false"); + log.error(startupErrorMessage.get()); } } else { log.error("Initializing applicationService failed", throwable); + startupErrorMessage.set(ExceptionUtil.getMessageOrToString(throwable)); } setState(State.FAILED); return false; @@ -274,13 +284,15 @@ public CompletableFuture shutdown() { .thenCompose(result -> walletService.map(Service::shutdown) .orElse(CompletableFuture.completedFuture(true))) .thenCompose(result -> securityService.shutdown()) - .orTimeout(10, TimeUnit.SECONDS) + .orTimeout(SHUTDOWN_TIMEOUT_SEC, TimeUnit.SECONDS) .handle((result, throwable) -> { if (throwable != null) { log.error("Error at shutdown", throwable); + shutDownErrorMessage.set(ExceptionUtil.getMessageOrToString(throwable)); return false; } else if (!result) { - log.error("Shutdown resulted with false"); + shutDownErrorMessage.set("Shutdown failed with result=false"); + log.error(startupErrorMessage.get()); return false; } return true; diff --git a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java index 8f961144b1..5303c3f34d 100644 --- a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java +++ b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java @@ -19,8 +19,10 @@ import bisq.application.Executable; import bisq.desktop.DesktopController; +import bisq.desktop.common.threading.UIScheduler; import bisq.desktop.common.threading.UIThread; import bisq.desktop.components.overlay.Popup; +import bisq.i18n.Res; import javafx.application.Application; import javafx.application.Platform; import lombok.extern.slf4j.Slf4j; @@ -33,6 +35,8 @@ public class DesktopExecutable extends Executable { @Nullable private DesktopController desktopController; + @Nullable + private Popup shutdownInProcessPopup; public DesktopExecutable(String[] args) { super(args); @@ -55,7 +59,9 @@ protected void launchApplication(String[] args) { if (throwable == null) { try { log.info("Java FX Application launched"); - desktopController = new DesktopController(applicationService.getState(), applicationService.getServiceProvider(), + setupStartupAndShutdownErrorHandlers(); + desktopController = new DesktopController(applicationService.getState(), + applicationService.getServiceProvider(), applicationData, this::onApplicationLaunched); desktopController.init(); @@ -95,11 +101,67 @@ protected void setDefaultUncaughtExceptionHandler() { }); } + @Override + protected void notifyAboutShutdown() { + if (shutdownInProcessPopup != null) { + return; + } + shutdownInProcessPopup = new Popup() + .headline(Res.get("action.shutDown")) + .feedback(Res.get("popup.shutdown", DesktopApplicationService.SHUTDOWN_TIMEOUT_SEC)); + shutdownInProcessPopup.hideCloseButton().show(); + } + @Override protected void exitJvm() { + if (applicationService.getShutDownErrorMessage().get() == null) { + doExit(); + } + // If we have an error popup we leave it to the user to close it and shutdown the app by clicking the shutdown button + } + + private void doExit() { log.info("Exiting JavaFX Platform"); Platform.exit(); - super.exitJvm(); } + + private void setupStartupAndShutdownErrorHandlers() { + applicationService.getStartupErrorMessage().addObserver(errorMessage -> { + if (errorMessage != null) { + UIThread.run(() -> + new Popup().error(Res.get("popup.startup.error", errorMessage)) + .closeButtonText(Res.get("action.shutDown")) + .onClose(this::doExit) + .show() + ); + } + }); + applicationService.getShutDownErrorMessage().addObserver(errorMessage -> { + if (errorMessage != null) { + UIThread.run(() -> { + if (shutdownInProcessPopup != null) { + shutdownInProcessPopup.hide(); + shutdownInProcessPopup = null; + } + Popup popup = new Popup(); + popup.error(Res.get("popup.shutdown.error", errorMessage)) + .closeButtonText(Res.get("action.shutDown")) + .onClose(this::doExit) + .show(); + // The error popup allow to report to GH, in that case we get closed the error popup. + // We leave the app open and reset the shutDownStarted flag, so that at another + // shutdown action shut down can happen. Only when the user clicks the close + // button we actually shut down. + popup.getIsHiddenProperty().addListener((observableValue, oldValue, newValue) -> { + if (newValue) { + shutDownStarted = false; + } + }); + // We reset the error so that it can get triggered again our error popup in case the user shutdown again. + UIScheduler.run(() -> applicationService.getShutDownErrorMessage().set(null)).after(1000); + }); + } + }); + } } diff --git a/i18n/src/main/resources/application.properties b/i18n/src/main/resources/application.properties index eddf6ffff8..6ae04d81d9 100644 --- a/i18n/src/main/resources/application.properties +++ b/i18n/src/main/resources/application.properties @@ -232,6 +232,10 @@ popup.reportError={0}\n\nTo help us to improve the software please report this b The above error message will be copied to the clipboard when you click any of the buttons below.\n\ It will make debugging easier if you include the bisq.log file by pressing 'Open log file', saving a copy, and attaching it to your bug report. popup.reportBug=Report bug to Bisq developers +popup.startup.error=An error occurred at initializing Bisq: {0}. +popup.shutdown=Shut down is in process.\n\n\ + It might take up to {0} seconds until shut down is completed. +popup.shutdown.error=An error occurred at shut down: {0}. #################################################################### From b448d3098da02d7ba3140691573dcce8830a09ab Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 15 Mar 2024 17:56:35 +0700 Subject: [PATCH 3/8] Add missing wrapping in UIThread --- .../accounts/PaymentAccountsController.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/accounts/PaymentAccountsController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/accounts/PaymentAccountsController.java index ea6f8b593c..8562200660 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/accounts/PaymentAccountsController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/user/accounts/PaymentAccountsController.java @@ -25,6 +25,7 @@ import bisq.common.observable.Pin; import bisq.desktop.ServiceProvider; import bisq.desktop.common.observable.FxBindings; +import bisq.desktop.common.threading.UIThread; import bisq.desktop.common.view.Controller; import bisq.desktop.common.view.Navigation; import bisq.i18n.Res; @@ -61,13 +62,15 @@ public void onActivate() { model.getSortedAccounts().setComparator(Comparator.comparing(Account::getAccountName)); accountsPin = accountService.getAccounts().addObserver(() -> { - model.setAllAccounts(accountService.getAccounts()); - maybeSelectFirstAccount(); - model.getNoAccountsSetup().set(!accountService.hasAccounts()); - model.getHeadline().set(accountService.hasAccounts() ? - Res.get("user.paymentAccounts.headline") : - Res.get("user.paymentAccounts.noAccounts.headline") - ); + UIThread.run(() -> { + model.setAllAccounts(accountService.getAccounts()); + maybeSelectFirstAccount(); + model.getNoAccountsSetup().set(!accountService.hasAccounts()); + model.getHeadline().set(accountService.hasAccounts() ? + Res.get("user.paymentAccounts.headline") : + Res.get("user.paymentAccounts.noAccounts.headline") + ); + }); }); selectedAccountPin = FxBindings.bind(model.selectedAccountProperty()) From 7736005875397be6c9c9ac900e2066b9b55216fe Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 15 Mar 2024 17:56:54 +0700 Subject: [PATCH 4/8] Change width of error popup --- .../src/main/java/bisq/desktop/components/overlay/Overlay.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/components/overlay/Overlay.java b/apps/desktop/desktop/src/main/java/bisq/desktop/components/overlay/Overlay.java index f0f7fe522b..cb4010b526 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/components/overlay/Overlay.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/components/overlay/Overlay.java @@ -405,7 +405,7 @@ public T error(Throwable throwable) { public T error(String message) { type = Type.ERROR; showReportErrorButtons(); - width = 1100; + width = 800; if (headline == null) this.headline = Res.get("popup.headline.error"); processMessage(message); From ebc9d8d343e59d64b281c66cd8c44868cb85ecda Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 15 Mar 2024 17:57:21 +0700 Subject: [PATCH 5/8] Reformat: Remove unneeded curly brackets --- .../trade_state/states/SellerState1.java | 36 +++++++++---------- .../bisq/desktop/splash/SplashController.java | 6 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/open_trades/trade_state/states/SellerState1.java b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/open_trades/trade_state/states/SellerState1.java index 7f8590f349..33543961e2 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/open_trades/trade_state/states/SellerState1.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/main/content/bisq_easy/open_trades/trade_state/states/SellerState1.java @@ -85,24 +85,24 @@ public void onActivate() { model.getSortedAccounts().setComparator(Comparator.comparing(Account::getAccountName)); - accountsPin = accountService.getAccounts().addObserver(() -> { - List accounts = accountService.getAccounts().stream() - .filter(account -> account instanceof UserDefinedFiatAccount) - .map(account -> (UserDefinedFiatAccount) account) - .collect(Collectors.toList()); - model.setAllAccounts(accounts); - model.getAccountSelectionVisible().set(accounts.size() > 1); - maybeSelectFirstAccount(); - }); - selectedAccountPin = accountService.selectedAccountAsObservable().addObserver(account -> { - UIThread.run(() -> { - if (account instanceof UserDefinedFiatAccount) { - UserDefinedFiatAccount userDefinedFiatAccount = (UserDefinedFiatAccount) account; - model.selectedAccountProperty().set(userDefinedFiatAccount); - model.getPaymentAccountData().set(userDefinedFiatAccount.getAccountPayload().getAccountData()); - } - }); - }); + accountsPin = accountService.getAccounts().addObserver(() -> + UIThread.run(() -> { + List accounts = accountService.getAccounts().stream() + .filter(account -> account instanceof UserDefinedFiatAccount) + .map(account -> (UserDefinedFiatAccount) account) + .collect(Collectors.toList()); + model.setAllAccounts(accounts); + model.getAccountSelectionVisible().set(accounts.size() > 1); + maybeSelectFirstAccount(); + })); + selectedAccountPin = accountService.selectedAccountAsObservable().addObserver(account -> + UIThread.run(() -> { + if (account instanceof UserDefinedFiatAccount) { + UserDefinedFiatAccount userDefinedFiatAccount = (UserDefinedFiatAccount) account; + model.selectedAccountProperty().set(userDefinedFiatAccount); + model.getPaymentAccountData().set(userDefinedFiatAccount.getAccountPayload().getAccountData()); + } + })); model.getButtonDisabled().bind(model.getPaymentAccountData().isEmpty()); findUsersAccountData().ifPresent(accountData -> model.getPaymentAccountData().set(accountData)); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/splash/SplashController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/splash/SplashController.java index 23b7982904..6232ae547a 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/splash/SplashController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/splash/SplashController.java @@ -50,9 +50,9 @@ public SplashController(Observable applicationServiceState, ServiceProvid @Override public void onActivate() { - applicationServiceStatePin = applicationServiceState.addObserver(state -> { - UIThread.run(() -> model.getApplicationServiceState().set(Res.get("splash.applicationServiceState." + state.name()))); - }); + applicationServiceStatePin = applicationServiceState.addObserver(state -> + UIThread.run(() -> model.getApplicationServiceState().set(Res.get("splash.applicationServiceState." + state.name()))) + ); if (networkService.getSupportedTransportTypes().contains(TransportType.CLEAR)) { model.getBootstrapStateDisplays().add(new BootstrapStateDisplay(TransportType.CLEAR, serviceProvider)); From 33baf1fca355780b28796eb25dece29164e6fbf9 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 15 Mar 2024 17:59:03 +0700 Subject: [PATCH 6/8] Wrap shutdown code into CompletableFuture.supplyAsync calls. --- .../main/java/bisq/updater/UpdaterService.java | 10 ++++++---- .../main/java/bisq/network/NetworkService.java | 15 +++++++++------ .../bisq/user/identity/UserIdentityService.java | 10 ++++++---- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/bisq/updater/UpdaterService.java b/application/src/main/java/bisq/updater/UpdaterService.java index 4445bec5d6..0cd222dde9 100644 --- a/application/src/main/java/bisq/updater/UpdaterService.java +++ b/application/src/main/java/bisq/updater/UpdaterService.java @@ -99,10 +99,12 @@ public void clear() { @Override public CompletableFuture shutdown() { - if (executorService != null) { - ExecutorFactory.shutdownAndAwaitTermination(executorService, 100); - } - return CompletableFuture.completedFuture(true); + return CompletableFuture.supplyAsync(() -> { + if (executorService != null) { + ExecutorFactory.shutdownAndAwaitTermination(executorService, 100); + } + return true; + }); } diff --git a/network/network/src/main/java/bisq/network/NetworkService.java b/network/network/src/main/java/bisq/network/NetworkService.java index e592515db4..729adbcf4e 100644 --- a/network/network/src/main/java/bisq/network/NetworkService.java +++ b/network/network/src/main/java/bisq/network/NetworkService.java @@ -205,12 +205,15 @@ public CompletableFuture initialize() { public CompletableFuture shutdown() { log.info("shutdown"); - messageDeliveryStatusService.ifPresent(MessageDeliveryStatusService::shutdown); - resendMessageService.ifPresent(ResendMessageService::shutdown); - networkLoadService.ifPresent(NetworkLoadService::shutdown); - dataService.ifPresent(DataService::shutdown); - return serviceNodesByTransport.shutdown() - .thenApply(list -> list.stream().filter(e -> e).count() == supportedTransportTypes.size()); + return CompletableFuture.supplyAsync(() -> { + messageDeliveryStatusService.ifPresent(MessageDeliveryStatusService::shutdown); + resendMessageService.ifPresent(ResendMessageService::shutdown); + networkLoadService.ifPresent(NetworkLoadService::shutdown); + dataService.ifPresent(DataService::shutdown); + return true; + }) + .thenCompose(result -> serviceNodesByTransport.shutdown() + .thenApply(list -> list.stream().filter(e -> e).count() == supportedTransportTypes.size())); } diff --git a/user/src/main/java/bisq/user/identity/UserIdentityService.java b/user/src/main/java/bisq/user/identity/UserIdentityService.java index f7b3cf85e2..7c31ece4d6 100644 --- a/user/src/main/java/bisq/user/identity/UserIdentityService.java +++ b/user/src/main/java/bisq/user/identity/UserIdentityService.java @@ -108,10 +108,12 @@ public CompletableFuture initialize() { } public CompletableFuture shutdown() { - if (rePublishUserProfilesExecutor != null) { - ExecutorFactory.shutdownAndAwaitTermination(rePublishUserProfilesExecutor); - } - return CompletableFuture.completedFuture(true); + return CompletableFuture.supplyAsync(() -> { + if (rePublishUserProfilesExecutor != null) { + ExecutorFactory.shutdownAndAwaitTermination(rePublishUserProfilesExecutor, 100); + } + return true; + }); } From 9c5d598628864dbbe3ebe726ae4ac86194fbe39d Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 15 Mar 2024 18:34:23 +0700 Subject: [PATCH 7/8] Wrap into UIThread --- .../main/java/bisq/desktop_app/DesktopExecutable.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java index 5303c3f34d..b348c30968 100644 --- a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java +++ b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java @@ -106,10 +106,12 @@ protected void notifyAboutShutdown() { if (shutdownInProcessPopup != null) { return; } - shutdownInProcessPopup = new Popup() - .headline(Res.get("action.shutDown")) - .feedback(Res.get("popup.shutdown", DesktopApplicationService.SHUTDOWN_TIMEOUT_SEC)); - shutdownInProcessPopup.hideCloseButton().show(); + UIThread.run(() -> { + shutdownInProcessPopup = new Popup() + .headline(Res.get("action.shutDown")) + .feedback(Res.get("popup.shutdown", DesktopApplicationService.SHUTDOWN_TIMEOUT_SEC)); + shutdownInProcessPopup.hideCloseButton().show(); + }); } @Override From db7eb9634b518d5d08f2a18901579a9804b89fe8 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 15 Mar 2024 18:40:21 +0700 Subject: [PATCH 8/8] Ignore "No toolkit found" exception if shutdown happens before we have JavaFX thread available --- .../java/bisq/desktop_app/DesktopExecutable.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java index b348c30968..edf3e892c6 100644 --- a/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java +++ b/apps/desktop/desktop-app/src/main/java/bisq/desktop_app/DesktopExecutable.java @@ -106,12 +106,15 @@ protected void notifyAboutShutdown() { if (shutdownInProcessPopup != null) { return; } - UIThread.run(() -> { - shutdownInProcessPopup = new Popup() - .headline(Res.get("action.shutDown")) - .feedback(Res.get("popup.shutdown", DesktopApplicationService.SHUTDOWN_TIMEOUT_SEC)); - shutdownInProcessPopup.hideCloseButton().show(); - }); + try { + UIThread.run(() -> { + shutdownInProcessPopup = new Popup() + .headline(Res.get("action.shutDown")) + .feedback(Res.get("popup.shutdown", DesktopApplicationService.SHUTDOWN_TIMEOUT_SEC)); + shutdownInProcessPopup.hideCloseButton().show(); + }); + } catch (Exception ignore) { + } } @Override