Skip to content

Commit

Permalink
Merge pull request #4410 from chimp1984/optimize-shutdown-routines
Browse files Browse the repository at this point in the history
Optimize application shutdown
  • Loading branch information
sqrrm authored Aug 28, 2020
2 parents 3599355 + 8e3b4d9 commit d1a1cc5
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 53 deletions.
77 changes: 43 additions & 34 deletions core/src/main/java/bisq/core/app/BisqExecutable.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public abstract class BisqExecutable implements GracefulShutDownHandler, BisqSet
protected Injector injector;
protected AppModule module;
protected Config config;
private boolean isShutdown = false;
private boolean isShutdownInProgress;

public BisqExecutable(String fullName, String scriptName, String appName, String version) {
this.fullName = fullName;
Expand Down Expand Up @@ -204,47 +204,56 @@ protected void startAppSetup() {
// This might need to be overwritten in case the application is not using all modules
@Override
public void gracefulShutDown(ResultHandler resultHandler) {
if (isShutdown) // prevent double cleanup
log.info("Start graceful shutDown");
if (isShutdownInProgress) {
return;
}

isShutdownInProgress = true;

if (injector == null) {
log.warn("Shut down called before injector was created");
resultHandler.handleResult();
System.exit(0);
}

isShutdown = true;
try {
if (injector != null) {
injector.getInstance(ArbitratorManager.class).shutDown();
injector.getInstance(TradeManager.class).shutDown();
injector.getInstance(DaoSetup.class).shutDown();
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
log.info("OpenOfferManager shutdown completed");
injector.getInstance(ArbitratorManager.class).shutDown();
injector.getInstance(TradeManager.class).shutDown();
injector.getInstance(DaoSetup.class).shutDown();
injector.getInstance(AvoidStandbyModeService.class).shutDown();
injector.getInstance(OpenOfferManager.class).shutDown(() -> {
log.info("OpenOfferManager shutdown completed");

injector.getInstance(BtcWalletService.class).shutDown();
injector.getInstance(BsqWalletService.class).shutDown();

// We need to shutdown BitcoinJ before the P2PService as it uses Tor.
WalletsSetup walletsSetup = injector.getInstance(WalletsSetup.class);
walletsSetup.shutDownComplete.addListener((ov, o, n) -> {
log.info("WalletsSetup shutdown completed");

injector.getInstance(P2PService.class).shutDown(() -> {
log.info("P2PService shutdown completed");
injector.getInstance(WalletsSetup.class).shutDownComplete.addListener((ov, o, n) -> {
log.info("WalletsSetup shutdown completed");
module.close(injector);
resultHandler.handleResult();
log.info("Graceful shutdown completed. Exiting now.");
System.exit(0);
});
injector.getInstance(WalletsSetup.class).shutDown();
injector.getInstance(BtcWalletService.class).shutDown();
injector.getInstance(BsqWalletService.class).shutDown();

module.close(injector);
resultHandler.handleResult();
log.info("Graceful shutdown completed. Exiting now.");
System.exit(0);
});
});
injector.getInstance(AvoidStandbyModeService.class).shutDown();
// we wait max 20 sec.
UserThread.runAfter(() -> {
log.warn("Timeout triggered resultHandler");
resultHandler.handleResult();
System.exit(0);
}, 20);
} else {
log.warn("injector == null triggered resultHandler");
UserThread.runAfter(() -> {
resultHandler.handleResult();
System.exit(0);
}, 1);
}
walletsSetup.shutDown();

});

// Wait max 20 sec.
UserThread.runAfter(() -> {
log.warn("Timeout triggered resultHandler");
resultHandler.handleResult();
System.exit(0);
}, 20);
} catch (Throwable t) {
log.error("App shutdown failed with exception");
log.error("App shutdown failed with exception {}", t.toString());
t.printStackTrace();
System.exit(1);
}
Expand Down
36 changes: 25 additions & 11 deletions core/src/main/java/bisq/core/btc/setup/WalletConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -492,8 +492,11 @@ void setPeerNodesForLocalHost() {
}
}

private Wallet createOrLoadWallet(File walletFile, boolean shouldReplayWallet,
BisqKeyChainGroup keyChainGroup, boolean isBsqWallet, DeterministicSeed restoreFromSeed)
private Wallet createOrLoadWallet(File walletFile,
boolean shouldReplayWallet,
BisqKeyChainGroup keyChainGroup,
boolean isBsqWallet,
DeterministicSeed restoreFromSeed)
throws Exception {

if (restoreFromSeed != null)
Expand Down Expand Up @@ -530,7 +533,9 @@ private void maybeMoveOldWalletOutOfTheWay(File vWalletFile) {
}
}

private Wallet loadWallet(File walletFile, boolean shouldReplayWallet, boolean useBitcoinDeterministicKeyChain) throws Exception {
private Wallet loadWallet(File walletFile,
boolean shouldReplayWallet,
boolean useBitcoinDeterministicKeyChain) throws Exception {
Wallet wallet;
try (FileInputStream walletStream = new FileInputStream(walletFile)) {
List<WalletExtension> extensions = provideWalletExtensions();
Expand Down Expand Up @@ -570,21 +575,30 @@ protected void shutDown() throws Exception {
// Runs in a separate thread.
try {
Context.propagate(context);
vPeerGroup.stop();

vBtcWallet.saveToFile(vBtcWalletFile);
if (vBsqWallet != null && vBsqWalletFile != null)
//noinspection ConstantConditions,ConstantConditions
vBtcWallet = null;
log.info("BtcWallet saved to file");

if (vBsqWallet != null && vBsqWalletFile != null) {
vBsqWallet.saveToFile(vBsqWalletFile);
vStore.close();
vBsqWallet = null;
log.info("BsqWallet saved to file");
}

vPeerGroup = null;
vBtcWallet = null;
vBsqWallet = null;
vStore.close();
vStore = null;
log.info("SPV file closed");

vChain = null;

// vPeerGroup.stop has no timeout and can take very long (10 sec. in my test). So we call it at the end.
// We might get likely interrupted by the parent call timeout.
vPeerGroup.stop();
vPeerGroup = null;
log.info("PeerGroup stopped");
} catch (BlockStoreException e) {
throw new IOException(e);
} catch (Throwable ignore) {
}
}

Expand Down
12 changes: 7 additions & 5 deletions core/src/main/java/bisq/core/btc/setup/WalletsSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package bisq.core.btc.setup;

import bisq.core.btc.exceptions.InvalidHostException;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.btc.exceptions.RejectedTxException;
import bisq.core.btc.model.AddressEntry;
import bisq.core.btc.model.AddressEntryList;
Expand All @@ -27,6 +26,7 @@
import bisq.core.btc.nodes.BtcNodes.BtcNode;
import bisq.core.btc.nodes.BtcNodesRepository;
import bisq.core.btc.nodes.BtcNodesSetupPreferences;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.user.Preferences;

import bisq.network.Socks5MultiDiscovery;
Expand Down Expand Up @@ -314,14 +314,16 @@ public void failed(@NotNull Service.State from, @NotNull Throwable failure) {
public void shutDown() {
if (walletConfig != null) {
try {
log.info("walletConfig shutDown started");
walletConfig.stopAsync();
walletConfig.awaitTerminated(5, TimeUnit.SECONDS);
walletConfig.awaitTerminated(1, TimeUnit.SECONDS);
log.info("walletConfig shutDown completed");
} catch (Throwable ignore) {
log.info("walletConfig shutDown interrupted by timeout");
}
shutDownComplete.set(true);
} else {
shutDownComplete.set(true);
}

shutDownComplete.set(true);
}

public void reSyncSPVChain() throws IOException {
Expand Down
13 changes: 10 additions & 3 deletions p2p/src/main/java/bisq/network/p2p/P2PService.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
private final IntegerProperty numConnectedPeers = new SimpleIntegerProperty(0);

private volatile boolean shutDownInProgress;
@Getter
private boolean shutDownComplete;
private final Subscription networkReadySubscription;
private boolean isBootstrapped;
Expand Down Expand Up @@ -446,7 +447,9 @@ public void onAdded(Collection<ProtectedStorageEntry> protectedStorageEntries) {
}

@Override
public void onRemoved(Collection<ProtectedStorageEntry> protectedStorageEntries) { }
public void onRemoved(Collection<ProtectedStorageEntry> protectedStorageEntries) {
// not handled
}

///////////////////////////////////////////////////////////////////////////////////////////
// DirectMessages
Expand All @@ -463,7 +466,9 @@ public void sendEncryptedDirectMessage(NodeAddress peerNodeAddress, PubKeyRing p
}
}

private void doSendEncryptedDirectMessage(@NotNull NodeAddress peersNodeAddress, PubKeyRing pubKeyRing, NetworkEnvelope message,
private void doSendEncryptedDirectMessage(@NotNull NodeAddress peersNodeAddress,
PubKeyRing pubKeyRing,
NetworkEnvelope message,
SendDirectMessageListener sendDirectMessageListener) {
log.debug("Send encrypted direct message {} to peer {}",
message.getClass().getSimpleName(), peersNodeAddress);
Expand Down Expand Up @@ -691,7 +696,9 @@ public void onBroadcastedToFirstPeer(BroadcastMessage message) {
}

@Override
public void onBroadcastCompleted(BroadcastMessage message, int numOfCompletedBroadcasts, int numOfFailedBroadcasts) {
public void onBroadcastCompleted(BroadcastMessage message,
int numOfCompletedBroadcasts,
int numOfFailedBroadcasts) {
log.info("Broadcast completed: Sent to {} peers (failed: {}). Message = {}",
numOfCompletedBroadcasts, numOfFailedBroadcasts, Utilities.toTruncatedString(message));
if (numOfCompletedBroadcasts == 0)
Expand Down
11 changes: 11 additions & 0 deletions p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -332,14 +332,25 @@ public void shutDown(Runnable shutDownCompleteHandler) {

Set<Connection> allConnections = getAllConnections();
int numConnections = allConnections.size();

if (numConnections == 0) {
log.info("Shutdown immediately because no connections are open.");
if (shutDownCompleteHandler != null) {
shutDownCompleteHandler.run();
}
return;
}

log.info("Shutdown {} connections", numConnections);

AtomicInteger shutdownCompleted = new AtomicInteger();
Timer timeoutHandler = UserThread.runAfter(() -> {
if (shutDownCompleteHandler != null) {
log.info("Shutdown completed due timeout");
shutDownCompleteHandler.run();
}
}, 3);

allConnections.forEach(c -> c.shutDown(CloseConnectionReason.APP_SHUT_DOWN,
() -> {
shutdownCompleted.getAndIncrement();
Expand Down

0 comments on commit d1a1cc5

Please sign in to comment.