LockRegistryLeaderInitiator перестает работать в тестах при изменении TestPropertySource

Я использую 3 x LockRegistryLeaderInitiatorчтобы управлять 3 x Candidate- БИЛЛИНГ, МОДЕЛЬ, ЭКСПОРТ. Я используюJdbcLockRegistry чтобы указать на мою встроенную базу данных H2.

У меня есть 3 теста JUnit для тестирования моих кандидатов BILLING, MODEL и EXPORT, которые выполняются последовательно.
Все используют@TestPropertySource. Но второй тест добавляет дополнительное свойство.

После запуска 1-го тестового класса, когда я останавливаюсь и пытаюсь перезапустить инициатор, он не запускается:

initiatorBilling.start();
while( !billing.isLeader() ) {
    Thread.sleep(500);
}

Я попытался заменить этот код на:

initiatorBilling.start();
while( !initiatorBilling.getContext().isLeader() ) {
    Thread.sleep(500);
}

но это тоже не работает.

Мой LockRegistryLeaderInitiatorКажется, перестали работать - все мои кандидаты НЕ лидеры, и даже после 5 минут ожидания они никогда не становятся лидерами. Обычно на консоль выводится сообщение о предоставлении / отмене лидерства каждому кандидату.

My DataSource - это встроенная база данных H2. Я не удаляю никакие таблицы или данные между классами JUnit.

Если я уточню @DirtiesContextв этих классах это действительно работает. Но у меня есть другие JUnits, которые используют этих кандидатов, которые также терпят неудачу, и мне кажется неправильным ставить@DirtiesContext в каждом отдельном JUnit, который у меня есть.

У меня создается впечатление, что мои инициаторы не воссоздаются и даже не уничтожаются между тестами. Я хотел бы знать, правильно ли я спроектировал это или это что-то глупое.

С помощью:

  • SpringBoot 1.5.22.РЕЛИЗ
  • весна-интеграция-jdbc 4.3.21.RELEASE
@Configuration
public class LeaderElectionConfiguration {
    
    @Bean
    public LockRegistry lockRegistry(LockRepository lockRepository) {
        return new JdbcLockRegistry(lockRepository);
    }

    @Bean
    public DefaultLockRepository lockRepository(DataSource dataSource) {
        return new FixedDefaultLockRepository(dataSource, UUID.randomUUID().toString());
    }

    @Bean(name = "billing")
    public LockRegistryLeaderInitiator leaderInitiatorBilling(LockRegistry lockRegistry, BillingLeaderCandidate billingCandidate) {
        LockRegistryLeaderInitiator lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator(lockRegistry, billingCandidate);
        lockRegistryLeaderInitiator.start();
        return lockRegistryLeaderInitiator;
    }

    @Bean(name="export")
    public LockRegistryLeaderInitiator leaderInitiatorExport(LockRegistry lockRegistry, ExportLeaderCandidate exportCandidate) {
        LockRegistryLeaderInitiator lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator(lockRegistry, exportCandidate);
        lockRegistryLeaderInitiator.start();
        return lockRegistryLeaderInitiator;
    }
    
    @Bean(name="model")
    public LockRegistryLeaderInitiator leaderInitiatorModel(LockRegistry lockRegistry, ModelSyncLeaderCandidate modelCandidate ) {
        LockRegistryLeaderInitiator lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator(lockRegistry, modelCandidate);
        lockRegistryLeaderInitiator.start();
        return lockRegistryLeaderInitiator;
    }
    
    @Bean
    public ModelSyncLeaderCandidate createModelCandidate() {
        return new ModelSyncLeaderCandidate();
    }
    @Bean
    public BillingLeaderCandidate createBillingCandidate() {
        return new BillingLeaderCandidate();
    }
    @Bean
    public ExportLeaderCandidate createExportCandidate() {
        return new ExportLeaderCandidate();
    }
}

Сделано это на основе проблемы другого пользователя, где, по-видимому, была ошибка при разблокировке вещей. Я подозреваю, что в этом больше нет необходимости.

public class FixedDefaultLockRepository extends DefaultLockRepository {

    public FixedDefaultLockRepository(DataSource dataSource, String id) {
        super(dataSource);
    }

    /**
     * Used to help fix a bug in the Spring implementation of DefaultLockRepository.
     */
    @Override
    public void delete(String lock) {
        try {
            super.delete(lock);
        } catch (Exception ex) {
            // Ignore exception on purpose.
        }
    }
public class ModelSyncLeaderCandidate extends GenericLeaderCandidate {

    public ModelSyncLeaderCandidate() {
        super(UUID.randomUUID().toString(), "MODEL_SYNC");
    }
}
public class BillingLeaderCandidate extends GenericLeaderCandidate {

    public BillingLeaderCandidate() {
        super(UUID.randomUUID().toString(), "BILLING");
    }
}
public class ExportLeaderCandidate extends GenericLeaderCandidate {

    public ExportLeaderCandidate() {
        super(UUID.randomUUID().toString(), "EXPORT_PREDICTIONS");
    }   
}

Юниты:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = { "db.embedded=true" })
public class LeaderCandidatesTest {
    @Autowired
    private BillingLeaderCandidate billing;
    
    @Autowired
    private ModelSyncLeaderCandidate model;
    
    @Autowired
    private ExportLeaderCandidate export;
    
    @Autowired
    @Qualifier("billing")
    private LockRegistryLeaderInitiator initiatorBilling;
    
    @Autowired
    @Qualifier("model")
    private LockRegistryLeaderInitiator initiatorModel;
    
    @Autowired
    @Qualifier("export")
    private LockRegistryLeaderInitiator initiatorExport;

    @Test
    public void candidatesAreLeadersByDefault() {
        assertTrue(billing.isLeader());
        assertTrue(model.isLeader());
        assertTrue(export.isLeader());
    }

    @Test
    public void billingLeaderChanged() throws InterruptedException {
        try {
            // Simulate losing Leadership
            initiatorBilling.stop();

            Thread.sleep(500);

            assertFalse(billing.isLeader());
        } finally {
            initiatorBilling.start();
            while( !billing.isLeader() ) {
                Thread.sleep(500);
            }
        }
    }

    @Test
    public void modelLeaderChanged() throws InterruptedException {
        try {
            // Simulate losing Leadership
            initiatorModel.stop();

            Thread.sleep(500);

            assertFalse(model.isLeader());
        } finally {
            initiatorModel.start();
            while( !initiatorModel.getContext().isLeader() ) {
                Thread.sleep(500);
                Thread.yield();
            }
        }
    }

    @Test
    public void exportLeaderChanged() throws InterruptedException {
        try {
            // Simulate losing Leadership
            initiatorExport.stop();

            Thread.sleep(500);

            assertFalse(export.isLeader());
        } finally {
            initiatorExport.start();
            while( !export.isLeader() ) {
                Thread.sleep(500);
            }
        }
    }
}
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = { "db.embedded=true","newProperty=doesntMatter" })
public class LeaderCandidatesTest2 {
    @Autowired
    private BillingLeaderCandidate billing;
    
    @Autowired
    private ModelSyncLeaderCandidate model;
    
    @Autowired
    private ExportLeaderCandidate export;
    
    @Autowired
    @Qualifier("billing")
    private LockRegistryLeaderInitiator initiatorBilling;
    
    @Autowired
    @Qualifier("model")
    private LockRegistryLeaderInitiator initiatorModel;
    
    @Autowired
    @Qualifier("export")
    private LockRegistryLeaderInitiator initiatorExport;

    @Test
    public void candidatesAreLeadersByDefault() {
        assertTrue(billing.isLeader());
        assertTrue(model.isLeader());
        assertTrue(export.isLeader());
    }

    @Test
    public void billingLeaderChanged() throws InterruptedException {
        try {
            // Simulate losing Leadership
            initiatorBilling.stop();

            Thread.sleep(500);

            assertFalse(billing.isLeader());
        } finally {
            initiatorBilling.start();
            while( !billing.isLeader() ) {
                Thread.sleep(500);
            }
        }
    }

    @Test
    public void modelLeaderChanged() throws InterruptedException {
        try {
            // Simulate losing Leadership
            initiatorModel.stop();

            Thread.sleep(500);

            assertFalse(model.isLeader());
        } finally {
            initiatorModel.start();
            while( !model.isLeader() ) {
                Thread.sleep(500);
            }
        }
    }

    @Test
    public void exportLeaderChanged() throws InterruptedException {
        try {
            // Simulate losing Leadership
            initiatorExport.stop();

            Thread.sleep(500);

            assertFalse(export.isLeader());
        } finally {
            initiatorExport.start();
            while( !export.isLeader() ) {
                Thread.sleep(500);
            }
        }
    }
}

ОБНОВЛЕНИЕ: похоже, это связано с тем, что я использую JdbcLockRegistry. Если вместо этого я использую DefaultLockRegistry, все работает нормально.

0 ответов

Другие вопросы по тегам