use of org.wildfly.clustering.group.Group in project quickstart by wildfly.
the class ServiceActivator method activate.
@Override
public void activate(ServiceActivatorContext serviceActivatorContext) {
try {
SingletonPolicy policy = (SingletonPolicy) serviceActivatorContext.getServiceRegistry().getRequiredService(ServiceName.parse(SingletonDefaultRequirement.SINGLETON_POLICY.getName())).awaitValue();
InjectedValue<Group> group = new InjectedValue<>();
Service<Node> primary = new SingletonService(true, group);
Service<Node> backup = new SingletonService(false, group);
policy.createSingletonServiceBuilder(SINGLETON_SERVICE_NAME, primary, backup).build(serviceActivatorContext.getServiceTarget()).addDependency(ServiceName.parse("org.wildfly.clustering.default-group"), Group.class, group).install();
LOG.info("Singleton service activated.");
} catch (InterruptedException e) {
throw new ServiceRegistryException(e);
}
}
use of org.wildfly.clustering.group.Group in project wildfly by wildfly.
the class AbstractDistributedSingletonService method providersChanged.
@Override
public synchronized void providersChanged(Set<Node> nodes) {
Group group = this.registry.get().getGroup();
List<Node> candidates = new ArrayList<>(group.getMembership().getMembers());
candidates.retainAll(nodes);
// Only run election on a single node
if (candidates.isEmpty() || candidates.get(0).equals(group.getLocalMember())) {
// First validate that quorum was met
int size = candidates.size();
boolean quorumMet = size >= this.quorum;
if ((this.quorum > 1) && (size == this.quorum)) {
// Log fragility of singleton availability
ClusteringServerLogger.ROOT_LOGGER.quorumJustReached(this.name.getCanonicalName(), this.quorum);
}
Node elected = quorumMet ? this.electionPolicy.elect(candidates) : null;
try {
if (elected != null) {
// Stop service on every node except elected node
for (Map.Entry<Node, CompletionStage<Void>> entry : this.dispatcher.executeOnGroup(new StopCommand(), elected).entrySet()) {
try {
entry.getValue().toCompletableFuture().join();
} catch (CancellationException e) {
ClusteringServerLogger.ROOT_LOGGER.tracef("Singleton service %s is not installed on %s", this.name.getCanonicalName(), entry.getKey().getName());
} catch (CompletionException e) {
Throwable cause = e.getCause();
if ((cause instanceof IllegalStateException) && (cause.getCause() instanceof ServiceNotFoundException)) {
ClusteringServerLogger.ROOT_LOGGER.debugf("Singleton service %s is no longer installed on %s", this.name.getCanonicalName(), entry.getKey().getName());
} else {
throw e;
}
}
}
// Start service on elected node
try {
this.dispatcher.executeOnMember(new StartCommand(), elected).toCompletableFuture().join();
} catch (CancellationException e) {
ClusteringServerLogger.ROOT_LOGGER.debugf("Singleton service %s could not be started on the elected primary singleton provider (%s) because it left the cluster. A new primary provider election will take place.", this.name.getCanonicalName(), elected.getName());
} catch (CompletionException e) {
Throwable cause = e.getCause();
if ((cause instanceof IllegalStateException) && (cause.getCause() instanceof ServiceNotFoundException)) {
ClusteringServerLogger.ROOT_LOGGER.debugf("Service % is no longer installed on the elected primary singleton provider (%s). A new primary provider election will take place.", this.name.getCanonicalName(), elected.getName());
} else {
throw e;
}
}
} else {
if (!quorumMet) {
ClusteringServerLogger.ROOT_LOGGER.quorumNotReached(this.name.getCanonicalName(), this.quorum);
}
// Stop service on every node
for (Map.Entry<Node, CompletionStage<Void>> entry : this.dispatcher.executeOnGroup(new StopCommand()).entrySet()) {
try {
entry.getValue().toCompletableFuture().join();
} catch (CancellationException e) {
ClusteringServerLogger.ROOT_LOGGER.tracef("Singleton service %s is not installed on %s", this.name.getCanonicalName(), entry.getKey().getName());
} catch (CompletionException e) {
Throwable cause = e.getCause();
if ((cause instanceof IllegalStateException) && (cause.getCause() instanceof ServiceNotFoundException)) {
ClusteringServerLogger.ROOT_LOGGER.debugf("Singleton service %s is no longer installed on %s", this.name.getCanonicalName(), entry.getKey().getName());
} else {
throw e;
}
}
}
}
if (this.electionListener != null) {
for (CompletionStage<Void> stage : this.dispatcher.executeOnGroup(new SingletonElectionCommand(candidates, elected)).values()) {
try {
stage.toCompletableFuture().join();
} catch (CancellationException e) {
// Ignore
}
}
}
} catch (CommandDispatcherException e) {
throw new IllegalStateException(e);
}
}
}
use of org.wildfly.clustering.group.Group in project wildfly by wildfly.
the class BeanExpirationSchedulerTestCase method testImmortal.
@Test
public void testImmortal() throws InterruptedException {
Group group = mock(Group.class);
Batcher<TransactionBatch> batcher = mock(Batcher.class);
BeanFactory<String, Object> factory = mock(BeanFactory.class);
ExpirationConfiguration<Object> config = mock(ExpirationConfiguration.class);
RemoveListener<Object> listener = mock(RemoveListener.class);
BeanEntry<String> entry = mock(BeanEntry.class);
BeanRemover<String, Object> remover = mock(BeanRemover.class);
String beanId = "immortal";
when(group.isSingleton()).thenReturn(true);
// Fun fact: the Jakarta Enterprise Beans specification allows a timeout value of 0, so only negative timeouts are treated as immortal
when(config.getTimeout()).thenReturn(Duration.ofMinutes(-1L));
when(config.getRemoveListener()).thenReturn(listener);
when(entry.getLastAccessedTime()).thenReturn(Instant.now());
try (Scheduler<String, ImmutableBeanEntry<String>> scheduler = new BeanExpirationScheduler<>(group, batcher, factory, config, remover, Duration.ZERO)) {
scheduler.schedule(beanId, entry);
Thread.sleep(500);
}
verify(batcher, never()).createBatch();
verify(remover, never()).remove(beanId, listener);
}
use of org.wildfly.clustering.group.Group in project wildfly by wildfly.
the class BeanExpirationSchedulerTestCase method testNotYetExpired.
@Test
public void testNotYetExpired() throws InterruptedException {
Group group = mock(Group.class);
Batcher<TransactionBatch> batcher = mock(Batcher.class);
TransactionBatch batch = mock(TransactionBatch.class);
BeanFactory<String, Object> factory = mock(BeanFactory.class);
ExpirationConfiguration<Object> config = mock(ExpirationConfiguration.class);
RemoveListener<Object> listener = mock(RemoveListener.class);
BeanEntry<String> entry = mock(BeanEntry.class);
BeanRemover<String, Object> remover = mock(BeanRemover.class);
String beanId = "not-expired";
Duration timeout = Duration.ofMillis(10L);
when(batcher.createBatch()).thenReturn(batch);
when(config.getTimeout()).thenReturn(Duration.ofMillis(1L));
when(config.getRemoveListener()).thenReturn(listener);
when(entry.getLastAccessedTime()).thenReturn(Instant.now().plus(Duration.ofMinutes(1)));
when(factory.findValue(beanId)).thenReturn(entry);
when(entry.isExpired(same(timeout))).thenReturn(false);
try (Scheduler<String, ImmutableBeanEntry<String>> scheduler = new BeanExpirationScheduler<>(group, batcher, factory, config, remover, Duration.ZERO)) {
scheduler.schedule(beanId, entry);
Thread.sleep(500);
}
verify(remover, never()).remove(beanId, listener);
verify(batch, never()).close();
}
use of org.wildfly.clustering.group.Group in project wildfly by wildfly.
the class BeanExpirationSchedulerTestCase method testCancel.
@Test
public void testCancel() throws InterruptedException {
Group group = mock(Group.class);
Batcher<TransactionBatch> batcher = mock(Batcher.class);
BeanFactory<String, Object> factory = mock(BeanFactory.class);
ExpirationConfiguration<Object> config = mock(ExpirationConfiguration.class);
RemoveListener<Object> listener = mock(RemoveListener.class);
BeanEntry<String> entry = mock(BeanEntry.class);
BeanRemover<String, Object> remover = mock(BeanRemover.class);
String beanId = "canceled";
Duration timeout = Duration.ofMinutes(1L);
when(config.getTimeout()).thenReturn(timeout);
when(config.getRemoveListener()).thenReturn(listener);
when(entry.getLastAccessedTime()).thenReturn(Instant.now());
try (Scheduler<String, ImmutableBeanEntry<String>> scheduler = new BeanExpirationScheduler<>(group, batcher, factory, config, remover, Duration.ZERO)) {
scheduler.schedule(beanId, entry);
Thread.sleep(500);
scheduler.cancel(beanId);
}
verify(remover, never()).remove(beanId, listener);
verify(batcher, never()).createBatch();
}
Aggregations