Skip to content

Commit

Permalink
Avoid doing interrupt on main thread when termination is requested
Browse files Browse the repository at this point in the history
This had some nasty side effects where ClosedByInterruptExceptions
prevented the system from shutdown properly.
  • Loading branch information
klaren authored and MishaDemianenko committed Jul 23, 2018
1 parent 66a478c commit 3332eca
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 25 deletions.
Expand Up @@ -49,8 +49,8 @@
public abstract class ServerBootstrapper implements Bootstrapper
{
public static final int OK = 0;
public static final int WEB_SERVER_STARTUP_ERROR_CODE = 1;
public static final int GRAPH_DATABASE_STARTUP_ERROR_CODE = 2;
private static final int WEB_SERVER_STARTUP_ERROR_CODE = 1;
private static final int GRAPH_DATABASE_STARTUP_ERROR_CODE = 2;
private static final String SIGTERM = "TERM";
private static final String SIGINT = "INT";

Expand Down Expand Up @@ -83,7 +83,7 @@ public static int start( Bootstrapper boot, String... argv )
public final int start( File homeDir, Optional<File> configFile, Map<String, String> configOverrides )
{
addShutdownHook();
installSignalHandler();
installSignalHandlers();
try
{
// Create config file from arguments
Expand Down Expand Up @@ -184,31 +184,18 @@ private static LogProvider setupLogging( Config config )
}

// Exit gracefully if possible
private void installSignalHandler()
private void installSignalHandlers()
{
installSignalHandler( SIGTERM ); // SIGTERM is invoked when system service is stopped
installSignalHandler( SIGINT ); // SIGINT is invoked when user hits ctrl-c when running `neo4j console`
}

private void installSignalHandler( String sig )
{
try
{
/*
* We want to interrupt the main thread which has start()ed lifecycle instances that may be blocked
* somewhere. If we don't do that, then the JVM will hang on the final join() for non daemon threads.
*/
Thread t = Thread.currentThread();
log.debug( "Installing signal handler to interrupt thread named " + t.getName() );
// SIGTERM is invoked when system service is stopped
Signal.handle( new Signal( SIGTERM ), signal ->
{
t.interrupt();
System.exit( 0 );
} );
}
catch ( Throwable e )
{
log.warn( "Unable to install signal handler. Exit code may not be 0 on graceful shutdown.", e );
}
try
{
// SIGINT is invoked when user hits ctrl-c when running `neo4j console`
Signal.handle( new Signal( SIGINT ), signal -> System.exit( 0 ) );
// System.exit() will trigger the shutdown hook
Signal.handle( new Signal( sig ), signal -> System.exit( 0 ) );
}
catch ( Throwable e )
{
Expand Down
@@ -0,0 +1,51 @@
package org.neo4j.causalclustering.discovery;

import org.junit.Test;

import java.util.UUID;

import org.neo4j.causalclustering.core.CausalClusteringSettings;
import org.neo4j.causalclustering.identity.MemberId;
import org.neo4j.kernel.configuration.BoltConnector;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.scheduler.CentralJobScheduler;
import org.neo4j.logging.NullLogProvider;
import org.neo4j.ports.allocation.PortAuthority;

import static org.neo4j.causalclustering.core.CausalClusteringSettings.initial_discovery_members;
import static org.neo4j.helpers.collection.MapUtil.stringMap;

public class HazelcastCoreTopologyServiceTest
{
@Test( timeout = 120_000)
public void shouldBeAbleToStartAndStoreWithoutSuccessfulJoin()
{
CentralJobScheduler jobScheduler = new CentralJobScheduler();
jobScheduler.init();
HostnameResolver hostnameResolver = new NoOpHostnameResolver();

// Random members that does not exists, discovery will never succeed
String initialHosts = "localhost:" + PortAuthority.allocatePort() + ",localhost:" + PortAuthority.allocatePort();
Config config = config();
config.augment( initial_discovery_members, initialHosts );
HazelcastCoreTopologyService service = new HazelcastCoreTopologyService( config,
new MemberId( UUID.randomUUID() ),
jobScheduler,
NullLogProvider.getInstance(),
NullLogProvider.getInstance(),
hostnameResolver,
new TopologyServiceNoRetriesStrategy() );
service.start();
Thread.yield();
service.stop();
}

private static Config config()
{
return Config.defaults( stringMap(
CausalClusteringSettings.raft_advertised_address.name(), "127.0.0.1:7000",
CausalClusteringSettings.transaction_advertised_address.name(), "127.0.0.1:7001",
new BoltConnector( "bolt" ).enabled.name(), "true",
new BoltConnector( "bolt" ).advertised_address.name(), "127.0.0.1:7002" ) );
}
}

0 comments on commit 3332eca

Please sign in to comment.