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, все работает нормально.