Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix networknode shutdown issues #4688

Merged
merged 3 commits into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions common/src/main/java/bisq/common/setup/CommonSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ protected static void setSystemProperties() {

protected static void setupSigIntHandlers(GracefulShutDownHandler gracefulShutDownHandler) {
Signal.handle(new Signal("INT"), signal -> {
gracefulShutDownHandler.gracefulShutDown(() -> {
});
UserThread.execute(() -> gracefulShutDownHandler.gracefulShutDown(() -> {
}));
});

Signal.handle(new Signal("TERM"), signal -> {
gracefulShutDownHandler.gracefulShutDown(() -> {
});
UserThread.execute(() -> gracefulShutDownHandler.gracefulShutDown(() -> {
}));
});
}

Expand Down
1 change: 0 additions & 1 deletion core/src/main/java/bisq/core/app/BisqSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ public void start() {
}

private void step2() {
torSetup.cleanupTorFiles();
readMapsFromResources(this::step3);
checkForCorrectOSArchitecture();
checkOSXVersion();
Expand Down
10 changes: 1 addition & 9 deletions core/src/main/java/bisq/core/app/TorSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,7 @@ public TorSetup(@Named(Config.TOR_DIR) File torDir) {
this.torDir = checkDir(torDir);
}

public void cleanupTorFiles() {
cleanupTorFiles(null, null);
}

// We get sometimes Tor startup problems which is related to some tor files in the tor directory. It happens
// more often if the application got killed (not graceful shutdown).
// Creating all tor files newly takes about 3-4 sec. longer and it does not benefit from cache files.
// TODO: We should fix those startup problems in the netlayer library, once fixed there we can remove that call at the
// Bisq startup again.
// Should only be called if needed. Slows down Tor startup from about 5 sec. to 30 sec. if it gets deleted.
public void cleanupTorFiles(@Nullable Runnable resultHandler, @Nullable ErrorMessageHandler errorMessageHandler) {
File hiddenservice = new File(Paths.get(torDir.getAbsolutePath(), "hiddenservice").toString());
try {
Expand Down
1 change: 0 additions & 1 deletion core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ public AppSetupWithP2P(P2PService p2PService,

@Override
public void initPersistedDataHosts() {
torSetup.cleanupTorFiles();
persistedDataHosts.add(p2PService);

// we apply at startup the reading of persisted data but don't want to get it triggered in the constructor
Expand Down
78 changes: 33 additions & 45 deletions p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import bisq.common.Timer;
import bisq.common.UserThread;
import bisq.common.proto.network.NetworkProtoResolver;
import bisq.common.util.Utilities;

import org.berndpruenster.netlayer.tor.HiddenServiceSocket;
import org.berndpruenster.netlayer.tor.Tor;
Expand Down Expand Up @@ -82,13 +81,14 @@ public class TorNetworkNode extends NetworkNode {
private boolean streamIsolation;

private Socks5Proxy socksProxy;
private ListenableFuture<Void> torStartupFuture;

///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////

public TorNetworkNode(int servicePort, NetworkProtoResolver networkProtoResolver, boolean useStreamIsolation,
TorMode torMode) {
TorMode torMode) {
super(servicePort, networkProtoResolver);
this.torMode = torMode;
this.streamIsolation = useStreamIsolation;
Expand Down Expand Up @@ -153,72 +153,60 @@ public void shutDown(@Nullable Runnable shutDownCompleteHandler) {
// this one is committed as a thread to the executor
BooleanProperty torNetworkNodeShutDown = torNetworkNodeShutDown();
BooleanProperty shutDownTimerTriggered = shutDownTimerTriggered();

// Need to store allShutDown to not get garbage collected
allShutDown = EasyBind.combine(torNetworkNodeShutDown, networkNodeShutDown, shutDownTimerTriggered, (a, b, c) -> (a && b) || c);
allShutDown = EasyBind.combine(torNetworkNodeShutDown, networkNodeShutDown, shutDownTimerTriggered,
(a, b, c) -> (a && b) || c);
allShutDown.subscribe((observable, oldValue, newValue) -> {
if (newValue) {
shutDownTimeoutTimer.stop();
long ts = System.currentTimeMillis();
log.debug("Shutdown executorService");
try {
MoreExecutors.shutdownAndAwaitTermination(executorService, 500, TimeUnit.MILLISECONDS);
log.debug("Shutdown executorService done after " + (System.currentTimeMillis() - ts) + " ms.");
log.debug("Shutdown completed");
log.debug("Shutdown executorService done after {} ms.", System.currentTimeMillis() - ts);
} catch (Throwable t) {
log.error("Shutdown executorService failed with exception: " + t.getMessage());
log.error("Shutdown executorService failed with exception: {}", t.getMessage());
t.printStackTrace();
} finally {
try {
if (shutDownCompleteHandler != null)
shutDownCompleteHandler.run();
} catch (Throwable ignore) {
}
if (shutDownCompleteHandler != null)
shutDownCompleteHandler.run();
}
}
});
}

private BooleanProperty torNetworkNodeShutDown() {
final BooleanProperty done = new SimpleBooleanProperty();
if (executorService != null) {
executorService.submit(() -> {
Utilities.setThreadName("torNetworkNodeShutDown");
long ts = System.currentTimeMillis();
log.debug("Shutdown torNetworkNode");
try {
/**
* make sure we get tor.
* - there have been situations where <code>tor</code> isn't set yet, which would leave tor running
* - downside is that if tor is not already started, we start it here just to shut it down. However,
* that can only be the case if Bisq gets shutdown even before it reaches step 2/4 at startup.
* The risk seems worth it compared to the risk of not shutting down tor.
*/
tor = Tor.getDefault();
if (tor != null)
tor.shutdown();
log.debug("Shutdown torNetworkNode done after " + (System.currentTimeMillis() - ts) + " ms.");
} catch (Throwable e) {
log.error("Shutdown torNetworkNode failed with exception: " + e.getMessage());
e.printStackTrace();
} finally {
UserThread.execute(() -> done.set(true));
}
});
} else {
done.set(true);
BooleanProperty done = new SimpleBooleanProperty();
try {
tor = Tor.getDefault();
if (tor != null) {
log.info("Tor has been created already so we can shut it down.");
tor.shutdown();
log.info("Tor shut down completed");
} else {
log.info("Tor has not been created yet. We cancel the torStartupFuture.");
torStartupFuture.cancel(true);
log.info("torStartupFuture cancelled");
}
} catch (Throwable e) {
log.error("Shutdown torNetworkNode failed with exception: {}", e.getMessage());
e.printStackTrace();

} finally {
// We need to delay as otherwise our listener would not get called if shutdown completes in synchronous manner
UserThread.execute(() -> done.set(true));
}
return done;
}

private BooleanProperty networkNodeShutDown() {
final BooleanProperty done = new SimpleBooleanProperty();
super.shutDown(() -> done.set(true));
BooleanProperty done = new SimpleBooleanProperty();
// We need to delay as otherwise our listener would not get called if shutdown completes in synchronous manner
UserThread.execute(() -> super.shutDown(() -> done.set(true)));
return done;
}

private BooleanProperty shutDownTimerTriggered() {
final BooleanProperty done = new SimpleBooleanProperty();
BooleanProperty done = new SimpleBooleanProperty();
shutDownTimeoutTimer = UserThread.runAfter(() -> {
log.error("A timeout occurred at shutDown");
done.set(true);
Expand Down Expand Up @@ -255,7 +243,7 @@ private void restartTor(String errorMessage) {
///////////////////////////////////////////////////////////////////////////////////////////

private void createTorAndHiddenService(int localPort, int servicePort) {
ListenableFuture<Void> future = executorService.submit(() -> {
torStartupFuture = executorService.submit(() -> {
try {
// get tor
Tor.setDefault(torMode.getTor());
Expand Down Expand Up @@ -313,7 +301,7 @@ public void run() {

return null;
});
Futures.addCallback(future, new FutureCallback<Void>() {
Futures.addCallback(torStartupFuture, new FutureCallback<Void>() {
public void onSuccess(Void ignore) {
}

Expand Down