Skip to content

Commit

Permalink
BranchNotFoundException on cluster initialization #9426
Browse files Browse the repository at this point in the history
  • Loading branch information
vbradnitski committed Apr 11, 2022
1 parent b8462e1 commit 7660b27
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,42 @@ protected Initializer( final Builder builder )
public void initialize()
{
final String initializationSubject = getInitializationSubject();
int failedCount = 0;

for ( int i = 0; i < initializationCheckMaxCount; i++ )
{
if ( readyToInitialize() )
{
final boolean initialized = isInitialized();
if ( initialized )
final boolean isGoingToInitialize = forceInitialization || isMaster();

try
{
LOG.debug( "Already initialized {}", initializationSubject );
return;
final boolean initialized = isInitialized();
if ( initialized )
{
LOG.debug( "Already initialized {}", initializationSubject );
return;
}
}
catch ( Exception e )
{
if ( isGoingToInitialize )
{
throw e;
}

if ( ++failedCount >= 10 || i == initializationCheckMaxCount - 1 )
{
failedCount = 0;
LOG.warn( "Problem during isInitialized check", e );
}
else
{
LOG.debug( "Problem during isInitialized check", e );
}
}

if ( forceInitialization || isMaster() )
if ( isGoingToInitialize )
{
LOG.info( "Initializing {}", initializationSubject );
doInitialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,75 +2,143 @@

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import com.enonic.xp.exception.InitializationException;

public class InitializerTest
{
@Test
public void testNonMaster()
{
final Runnable doInitalization = Mockito.mock( Runnable.class );
final Runnable doInitialization = Mockito.mock( Runnable.class );
final Supplier<Boolean> isInitialized = Mockito.mock( Supplier.class );
Mockito.when( isInitialized.get() ).thenReturn( false );

final long willInitializeIn = 100L;

final TestInitializer initializer = TestInitializer.create().
setInitializationCheckMaxCount( willInitializeIn * 2L ).
setInitializationCheckPeriod( 1L ).
setMaster( false ).
setInitialized( false ).
setInitialization( doInitalization ).
build();
final TestInitializer initializer = TestInitializer.create()
.setInitializationCheckMaxCount( willInitializeIn * 2L )
.setInitializationCheckPeriod( 1L )
.setMaster( false )
.setIsInitialized( isInitialized )
.setInitialization( doInitialization )
.build();

CompletableFuture.runAsync( () -> initializer.setInitialized( true ),
CompletableFuture.runAsync( () -> initializer.setIsInitialized( () -> true ),
CompletableFuture.delayedExecutor( willInitializeIn, TimeUnit.MILLISECONDS ) );
initializer.initialize();
Mockito.verify( doInitalization, Mockito.never() ).run();

Mockito.verify( doInitialization, Mockito.never() ).run();
Mockito.verify( isInitialized, Mockito.atLeastOnce() ).get();
}

@Test
public void testMaster()
{
final Runnable doInitalization = Mockito.mock( Runnable.class );
final TestInitializer initializer = TestInitializer.create().
setMaster( true ).
setInitialized( false ).
setInitialization( doInitalization ).
build();
final Runnable doInitialization = Mockito.mock( Runnable.class );
final TestInitializer initializer =
TestInitializer.create().setMaster( true ).setIsInitialized( () -> false ).setInitialization( doInitialization ).build();

initializer.initialize();

Mockito.verify( doInitalization ).run();
Mockito.verify( doInitialization ).run();
}

@Test
public void testNonMasterInitialized()
{
final Runnable doInitalization = Mockito.mock( Runnable.class );
final TestInitializer initializer = TestInitializer.create().
setMaster( false ).
setInitialized( true ).
setInitialization( doInitalization ).
build();
final Runnable doInitialization = Mockito.mock( Runnable.class );
final Supplier<Boolean> isInitialized = Mockito.mock( Supplier.class );
Mockito.when( isInitialized.get() ).thenReturn( true );

final TestInitializer initializer =
TestInitializer.create().setMaster( false ).setIsInitialized( isInitialized ).setInitialization( doInitialization ).build();

initializer.initialize();

Mockito.verify( doInitalization, Mockito.never() ).run();
Mockito.verify( doInitialization, Mockito.never() ).run();
Mockito.verify( isInitialized, Mockito.only() ).get();
}

@Test
public void testMasterInitialized()
{
final Runnable doInitalization = Mockito.mock( Runnable.class );
final TestInitializer initializer = TestInitializer.create().
setMaster( true ).
setInitialized( true ).
setInitialization( doInitalization ).
build();
final Runnable doInitialization = Mockito.mock( Runnable.class );
final TestInitializer initializer =
TestInitializer.create().setMaster( true ).setIsInitialized( () -> true ).setInitialization( doInitialization ).build();

initializer.initialize();

Mockito.verify( doInitalization, Mockito.never() ).run();
Mockito.verify( doInitialization, Mockito.never() ).run();
}

@Test
public void testNonMasterFailed()
{
final long willInitializeIn = 1000L;

final TestInitializer initializer = TestInitializer.create()
.setInitializationCheckMaxCount( 100L )
.setInitializationCheckPeriod( 1L )
.setMaster( false )
.setIsInitialized( () -> false )
.setInitialization( () -> {
} )
.build();

CompletableFuture.runAsync( () -> initializer.setIsInitialized( () -> true ),
CompletableFuture.delayedExecutor( willInitializeIn, TimeUnit.MILLISECONDS ) );

Assertions.assertThrows( InitializationException.class, initializer::initialize );
}

@Test
public void testIsInitializedFailedInNonMaster()
{
final long willInitializeIn = 1000L;

final TestInitializer initializer = TestInitializer.create()
.setInitializationCheckMaxCount( 100L )
.setInitializationCheckPeriod( 1L )
.setMaster( false )
.setIsInitialized( () -> {
throw new RuntimeException();
} )
.setInitialization( () -> {
} )
.build();

CompletableFuture.runAsync( () -> initializer.setIsInitialized( () -> true ),
CompletableFuture.delayedExecutor( willInitializeIn, TimeUnit.MILLISECONDS ) );

Assertions.assertThrows( InitializationException.class, initializer::initialize );
}

@Test
public void testIsInitializedFailedInMaster()
{
final long willInitializeIn = 1000L;

final TestInitializer initializer = TestInitializer.create()
.setInitializationCheckMaxCount( 100L )
.setInitializationCheckPeriod( 1L )
.setMaster( true )
.setIsInitialized( () -> {
throw new RuntimeException( "exception message" );
} )
.setInitialization( () -> {
} )
.build();

CompletableFuture.runAsync( () -> initializer.setIsInitialized( () -> true ),
CompletableFuture.delayedExecutor( willInitializeIn, TimeUnit.MILLISECONDS ) );

final RuntimeException ex = Assertions.assertThrows( RuntimeException.class, initializer::initialize );
Assertions.assertEquals( "exception message", ex.getMessage() );
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package com.enonic.xp.init;

import java.util.function.Supplier;

public class TestInitializer
extends Initializer
{
private final boolean isMaster;

private volatile boolean initialized;

private final Runnable initialization;

private Supplier<Boolean> isInitialized;

public TestInitializer( final Builder builder )
{
super( builder );
this.isMaster = builder.isMaster;
this.initialized = builder.initialized;
this.initialization = builder.initialization;
this.isInitialized = builder.isInitialized;
}

@Override
Expand All @@ -26,7 +28,7 @@ protected boolean isMaster()
@Override
protected boolean isInitialized()
{
return initialized;
return isInitialized.get();
}

@Override
Expand All @@ -35,9 +37,9 @@ protected boolean readyToInitialize()
return true;
}

protected void setInitialized( final boolean initialized )
protected void setIsInitialized( final Supplier<Boolean> isInitialized )
{
this.initialized = initialized;
this.isInitialized = isInitialized;
}

@Override
Expand All @@ -62,25 +64,25 @@ public static class Builder
{
private boolean isMaster;

private boolean initialized;

private Runnable initialization;

private Supplier<Boolean> isInitialized;

public Builder setMaster( final boolean master )
{
isMaster = master;
return this;
}

public Builder setInitialized( final boolean initialized )
public Builder setInitialization( final Runnable initialization )
{
this.initialized = initialized;
this.initialization = initialization;
return this;
}

public Builder setInitialization( final Runnable initialization )
public Builder setIsInitialized( final Supplier<Boolean> isInitialized )
{
this.initialization = initialization;
this.isInitialized = isInitialized;
return this;
}

Expand Down

0 comments on commit 7660b27

Please sign in to comment.