Commit 34d4f127 by kevin peters Committed by Johannes Edmeier

Prevent SBA Client's TaskScheduler to be picked up by @Scheduled

The TaskScheduler used for periodically registering is removed from the application context and moved to the ApplicationRegistrationListener. see #478
parent 9a80b625
......@@ -29,7 +29,6 @@ import java.util.Collections;
import java.util.List;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
......@@ -46,8 +45,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import static org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
......@@ -107,21 +104,10 @@ public class SpringBootAdminClientAutoConfiguration {
}
@Bean
@Qualifier("registrationTaskScheduler")
public TaskScheduler registrationTaskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(1);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("registrationTask");
return taskScheduler;
}
@Bean
@ConditionalOnMissingBean
public RegistrationApplicationListener registrationListener(ClientProperties client,
ApplicationRegistrator registrator) {
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator,
registrationTaskScheduler());
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator);
listener.setAutoRegister(client.isAutoRegistration());
listener.setAutoDeregister(client.isAutoDeregistration());
listener.setRegisterPeriod(client.getPeriod());
......
......@@ -20,12 +20,14 @@ import java.time.Duration;
import java.util.concurrent.ScheduledFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* Listener responsible for starting and stopping the registration task when the application is
......@@ -33,16 +35,28 @@ import org.springframework.scheduling.TaskScheduler;
*
* @author Johannes Edmeier
*/
public class RegistrationApplicationListener {
public class RegistrationApplicationListener implements InitializingBean, DisposableBean {
private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationApplicationListener.class);
private final ApplicationRegistrator registrator;
private final TaskScheduler taskScheduler;
private final ThreadPoolTaskScheduler taskScheduler;
private boolean autoDeregister = false;
private boolean autoRegister = true;
private Duration registerPeriod = Duration.ofSeconds(10);
private volatile ScheduledFuture<?> scheduledTask;
public RegistrationApplicationListener(ApplicationRegistrator registrator, TaskScheduler taskScheduler) {
public RegistrationApplicationListener(ApplicationRegistrator registrator) {
this(registrator, registrationTaskScheduler());
}
private static ThreadPoolTaskScheduler registrationTaskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(1);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("registrationTask");
return taskScheduler;
}
RegistrationApplicationListener(ApplicationRegistrator registrator, ThreadPoolTaskScheduler taskScheduler) {
this.registrator = registrator;
this.taskScheduler = taskScheduler;
}
......@@ -94,4 +108,14 @@ public class RegistrationApplicationListener {
public void setRegisterPeriod(Duration registerPeriod) {
this.registerPeriod = registerPeriod;
}
@Override
public void afterPropertiesSet() {
taskScheduler.afterPropertiesSet();
}
@Override
public void destroy() {
taskScheduler.destroy();
}
}
......@@ -22,7 +22,7 @@ import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.WebApplicationContext;
......@@ -30,15 +30,16 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class RegistrationApplicationListenerTest {
@Test
public void test_register() {
public void should_schedule_register_task() {
ApplicationRegistrator registrator = mock(ApplicationRegistrator.class);
TaskScheduler scheduler = mock(TaskScheduler.class);
ThreadPoolTaskScheduler scheduler = mock(ThreadPoolTaskScheduler.class);
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator, scheduler);
listener.onApplicationReady(new ApplicationReadyEvent(mock(SpringApplication.class), null,
......@@ -48,9 +49,9 @@ public class RegistrationApplicationListenerTest {
}
@Test
public void test_no_register() {
public void should_no_schedule_register_task_when_not_autoRegister() {
ApplicationRegistrator registrator = mock(ApplicationRegistrator.class);
TaskScheduler scheduler = mock(TaskScheduler.class);
ThreadPoolTaskScheduler scheduler = mock(ThreadPoolTaskScheduler.class);
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator, scheduler);
listener.setAutoRegister(false);
......@@ -60,34 +61,31 @@ public class RegistrationApplicationListenerTest {
verify(scheduler, never()).scheduleAtFixedRate(isA(Runnable.class), eq(Duration.ofSeconds(10)));
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Test
public void test_no_register_after_close() {
public void should_cancel_register_task_on_context_close() {
ApplicationRegistrator registrator = mock(ApplicationRegistrator.class);
TaskScheduler scheduler = mock(TaskScheduler.class);
ThreadPoolTaskScheduler scheduler = mock(ThreadPoolTaskScheduler.class);
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator, scheduler);
ScheduledFuture task = mock(ScheduledFuture.class);
when(scheduler.scheduleAtFixedRate(isA(Runnable.class), eq(Duration.ofSeconds(10)))).thenReturn(task);
ScheduledFuture<?> task = mock(ScheduledFuture.class);
when(scheduler.scheduleAtFixedRate(isA(Runnable.class), eq(Duration.ofSeconds(10)))).then(invocation -> task);
listener.onApplicationReady(new ApplicationReadyEvent(mock(SpringApplication.class), null,
mock(ConfigurableWebApplicationContext.class)));
verify(scheduler).scheduleAtFixedRate(isA(Runnable.class), eq(Duration.ofSeconds(10)));
listener.onClosedContext(new ContextClosedEvent(mock(WebApplicationContext.class)));
verify(task).cancel(true);
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Test
public void test_start_stop() {
public void should_start_and_cancel_task_on_request() {
ApplicationRegistrator registrator = mock(ApplicationRegistrator.class);
TaskScheduler scheduler = mock(TaskScheduler.class);
ThreadPoolTaskScheduler scheduler = mock(ThreadPoolTaskScheduler.class);
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator, scheduler);
ScheduledFuture task = mock(ScheduledFuture.class);
when(scheduler.scheduleAtFixedRate(isA(Runnable.class), eq(Duration.ofSeconds(10)))).thenReturn(task);
ScheduledFuture<?> task = mock(ScheduledFuture.class);
when(scheduler.scheduleAtFixedRate(isA(Runnable.class), eq(Duration.ofSeconds(10)))).then(invocation -> task);
listener.startRegisterTask();
verify(scheduler).scheduleAtFixedRate(isA(Runnable.class), eq(Duration.ofSeconds(10)));
......@@ -97,9 +95,9 @@ public class RegistrationApplicationListenerTest {
}
@Test
public void test_no_deregister() {
public void should_not_deregister_when_not_autoDeregister() {
ApplicationRegistrator registrator = mock(ApplicationRegistrator.class);
TaskScheduler scheduler = mock(TaskScheduler.class);
ThreadPoolTaskScheduler scheduler = mock(ThreadPoolTaskScheduler.class);
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator, scheduler);
listener.onClosedContext(new ContextClosedEvent(mock(WebApplicationContext.class)));
......@@ -108,9 +106,9 @@ public class RegistrationApplicationListenerTest {
}
@Test
public void test_deregister() {
public void should_deregister_when_autoDeregister() {
ApplicationRegistrator registrator = mock(ApplicationRegistrator.class);
TaskScheduler scheduler = mock(TaskScheduler.class);
ThreadPoolTaskScheduler scheduler = mock(ThreadPoolTaskScheduler.class);
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator, scheduler);
listener.setAutoDeregister(true);
......@@ -118,4 +116,17 @@ public class RegistrationApplicationListenerTest {
verify(registrator).deregister();
}
@Test
public void should_init_and_shutdown_taskScheduler() {
ApplicationRegistrator registrator = mock(ApplicationRegistrator.class);
ThreadPoolTaskScheduler scheduler = mock(ThreadPoolTaskScheduler.class);
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator, scheduler);
listener.afterPropertiesSet();
verify(scheduler, times(1)).afterPropertiesSet();
listener.destroy();
verify(scheduler, times(1)).destroy();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment