Add an endpoint for retrieving information about scheduled tasks
Closes gh-8831
This commit is contained in:
parent
370453c765
commit
1a094598b8
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.actuate.autoconfigure.scheduling;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
|
||||||
|
import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTaskHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EnableAutoConfiguration Auto-configuration} for {@link ScheduledTasksEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public class ScheduledTasksEndpointAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
@ConditionalOnEnabledEndpoint
|
||||||
|
public ScheduledTasksEndpoint scheduledTasksEndpoint(
|
||||||
|
ObjectProvider<List<ScheduledTaskHolder>> holders) {
|
||||||
|
return new ScheduledTasksEndpoint(holders.getIfAvailable(Collections::emptyList));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration,
|
||||||
org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoConfiguration,\
|
org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoConfiguration,\
|
||||||
org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\
|
org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\
|
||||||
org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\
|
org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\
|
||||||
|
org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration,\
|
||||||
org.springframework.boot.actuate.autoconfigure.session.SessionsEndpointAutoConfiguration,\
|
org.springframework.boot.actuate.autoconfigure.session.SessionsEndpointAutoConfiguration,\
|
||||||
org.springframework.boot.actuate.autoconfigure.solr.SolrHealthIndicatorAutoConfiguration,\
|
org.springframework.boot.actuate.autoconfigure.solr.SolrHealthIndicatorAutoConfiguration,\
|
||||||
org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorAutoConfiguration,\
|
org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorAutoConfiguration,\
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.actuate.autoconfigure.scheduling;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link ScheduledTasksEndpointAutoConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class ScheduledTasksEndpointAutoConfigurationTests {
|
||||||
|
|
||||||
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
|
.withConfiguration(
|
||||||
|
AutoConfigurations.of(ScheduledTasksEndpointAutoConfiguration.class));
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void endpointIsAutoConfigured() {
|
||||||
|
this.contextRunner.run((context) -> assertThat(context)
|
||||||
|
.hasSingleBean(ScheduledTasksEndpoint.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void endpointCanBeDisabled() {
|
||||||
|
this.contextRunner.withPropertyValues("endpoints.scheduledtasks.enabled:false")
|
||||||
|
.run((context) -> assertThat(context)
|
||||||
|
.doesNotHaveBean(ScheduledTasksEndpoint.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void endpointBacksOffWhenUserProvidedEndpointIsPresent() {
|
||||||
|
this.contextRunner.withUserConfiguration(CustomEndpointConfiguration.class)
|
||||||
|
.run((context) -> assertThat(context)
|
||||||
|
.hasSingleBean(ScheduledTasksEndpoint.class)
|
||||||
|
.hasBean("customEndpoint"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CustomEndpointConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CustomEndpoint customEndpoint() {
|
||||||
|
return new CustomEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class CustomEndpoint extends ScheduledTasksEndpoint {
|
||||||
|
|
||||||
|
private CustomEndpoint() {
|
||||||
|
super(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,284 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.actuate.scheduling;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||||
|
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||||
|
import org.springframework.scheduling.Trigger;
|
||||||
|
import org.springframework.scheduling.config.CronTask;
|
||||||
|
import org.springframework.scheduling.config.FixedDelayTask;
|
||||||
|
import org.springframework.scheduling.config.FixedRateTask;
|
||||||
|
import org.springframework.scheduling.config.IntervalTask;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTask;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTaskHolder;
|
||||||
|
import org.springframework.scheduling.config.Task;
|
||||||
|
import org.springframework.scheduling.config.TriggerTask;
|
||||||
|
import org.springframework.scheduling.support.CronTrigger;
|
||||||
|
import org.springframework.scheduling.support.PeriodicTrigger;
|
||||||
|
import org.springframework.scheduling.support.ScheduledMethodRunnable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Endpoint} to expose information about an application's scheduled tasks.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
@Endpoint(id = "scheduledtasks")
|
||||||
|
public class ScheduledTasksEndpoint {
|
||||||
|
|
||||||
|
private final Collection<ScheduledTaskHolder> scheduledTaskHolders;
|
||||||
|
|
||||||
|
public ScheduledTasksEndpoint(Collection<ScheduledTaskHolder> scheduledTaskHolders) {
|
||||||
|
this.scheduledTaskHolders = scheduledTaskHolders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReadOperation
|
||||||
|
public ScheduledTasksReport scheduledTasks() {
|
||||||
|
Map<TaskType, List<TaskDescription>> descriptionsByType = this.scheduledTaskHolders
|
||||||
|
.stream().flatMap((holder) -> holder.getScheduledTasks().stream())
|
||||||
|
.map(ScheduledTask::getTask).map(TaskDescription::of)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.groupingBy(TaskDescription::getType));
|
||||||
|
return new ScheduledTasksReport(descriptionsByType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A report of an application's scheduled {@link Task Tasks}, primarily intended for
|
||||||
|
* serialization to JSON.
|
||||||
|
*/
|
||||||
|
public static final class ScheduledTasksReport {
|
||||||
|
|
||||||
|
private final List<TaskDescription> cron;
|
||||||
|
|
||||||
|
private final List<TaskDescription> fixedDelay;
|
||||||
|
|
||||||
|
private final List<TaskDescription> fixedRate;
|
||||||
|
|
||||||
|
private ScheduledTasksReport(
|
||||||
|
Map<TaskType, List<TaskDescription>> descriptionsByType) {
|
||||||
|
this.cron = descriptionsByType.getOrDefault(TaskType.CRON,
|
||||||
|
Collections.emptyList());
|
||||||
|
this.fixedDelay = descriptionsByType.getOrDefault(TaskType.FIXED_DELAY,
|
||||||
|
Collections.emptyList());
|
||||||
|
this.fixedRate = descriptionsByType.getOrDefault(TaskType.FIXED_RATE,
|
||||||
|
Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TaskDescription> getCron() {
|
||||||
|
return this.cron;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TaskDescription> getFixedDelay() {
|
||||||
|
return this.fixedDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TaskDescription> getFixedRate() {
|
||||||
|
return this.fixedRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for descriptions of a {@link Task}.
|
||||||
|
*/
|
||||||
|
public static abstract class TaskDescription {
|
||||||
|
|
||||||
|
private static final Map<Class<? extends Task>, Function<Task, TaskDescription>> describers = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
describers.put(FixedRateTask.class,
|
||||||
|
(task) -> new FixedRateTaskDescription((FixedRateTask) task));
|
||||||
|
describers.put(FixedDelayTask.class,
|
||||||
|
(task) -> new FixedDelayTaskDescription((FixedDelayTask) task));
|
||||||
|
describers.put(CronTask.class,
|
||||||
|
(task) -> new CronTaskDescription((CronTask) task));
|
||||||
|
describers.put(TriggerTask.class,
|
||||||
|
(task) -> describeTriggerTask((TriggerTask) task));
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskType type;
|
||||||
|
|
||||||
|
private final RunnableDescription runnable;
|
||||||
|
|
||||||
|
private static TaskDescription of(Task task) {
|
||||||
|
return describers.entrySet().stream()
|
||||||
|
.filter((entry) -> entry.getKey().isInstance(task))
|
||||||
|
.map((entry) -> entry.getValue().apply(task)).findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TaskDescription describeTriggerTask(TriggerTask triggerTask) {
|
||||||
|
Trigger trigger = triggerTask.getTrigger();
|
||||||
|
if (trigger instanceof CronTrigger) {
|
||||||
|
return new CronTaskDescription(triggerTask, (CronTrigger) trigger);
|
||||||
|
}
|
||||||
|
if (trigger instanceof PeriodicTrigger) {
|
||||||
|
PeriodicTrigger periodicTrigger = (PeriodicTrigger) trigger;
|
||||||
|
if (periodicTrigger.isFixedRate()) {
|
||||||
|
return new FixedRateTaskDescription(triggerTask, periodicTrigger);
|
||||||
|
}
|
||||||
|
return new FixedDelayTaskDescription(triggerTask, periodicTrigger);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TaskDescription(TaskType type, Runnable runnable) {
|
||||||
|
this.type = type;
|
||||||
|
this.runnable = new RunnableDescription(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskType getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final RunnableDescription getRunnable() {
|
||||||
|
return this.runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of an {@link IntervalTask}.
|
||||||
|
*/
|
||||||
|
public static class IntervalTaskDescription extends TaskDescription {
|
||||||
|
|
||||||
|
private final long initialDelay;
|
||||||
|
|
||||||
|
private final long interval;
|
||||||
|
|
||||||
|
protected IntervalTaskDescription(TaskType type, IntervalTask task) {
|
||||||
|
super(type, task.getRunnable());
|
||||||
|
this.initialDelay = task.getInitialDelay();
|
||||||
|
this.interval = task.getInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IntervalTaskDescription(TaskType type, TriggerTask task,
|
||||||
|
PeriodicTrigger trigger) {
|
||||||
|
super(type, task.getRunnable());
|
||||||
|
this.initialDelay = trigger.getInitialDelay();
|
||||||
|
this.interval = trigger.getPeriod();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getInitialDelay() {
|
||||||
|
return this.initialDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getInterval() {
|
||||||
|
return this.interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of a {@link FixedDelayTask} or a {@link TriggerTask} with a
|
||||||
|
* fixed-delay {@link PeriodicTrigger}.
|
||||||
|
*/
|
||||||
|
public static final class FixedDelayTaskDescription extends IntervalTaskDescription {
|
||||||
|
|
||||||
|
private FixedDelayTaskDescription(FixedDelayTask task) {
|
||||||
|
super(TaskType.FIXED_DELAY, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FixedDelayTaskDescription(TriggerTask task, PeriodicTrigger trigger) {
|
||||||
|
super(TaskType.FIXED_DELAY, task, trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of a {@link FixedRateTask} or a {@link TriggerTask} with a fixed-rate
|
||||||
|
* {@link PeriodicTrigger}.
|
||||||
|
*/
|
||||||
|
public static final class FixedRateTaskDescription extends IntervalTaskDescription {
|
||||||
|
|
||||||
|
private FixedRateTaskDescription(FixedRateTask task) {
|
||||||
|
super(TaskType.FIXED_RATE, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FixedRateTaskDescription(TriggerTask task, PeriodicTrigger trigger) {
|
||||||
|
super(TaskType.FIXED_RATE, task, trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of an {@link CronTask} or a {@link TriggerTask} with a
|
||||||
|
* {@link CronTrigger}.
|
||||||
|
*/
|
||||||
|
public static final class CronTaskDescription extends TaskDescription {
|
||||||
|
|
||||||
|
private final String expression;
|
||||||
|
|
||||||
|
private CronTaskDescription(CronTask task) {
|
||||||
|
super(TaskType.CRON, task.getRunnable());
|
||||||
|
this.expression = task.getExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CronTaskDescription(TriggerTask task, CronTrigger trigger) {
|
||||||
|
super(TaskType.CRON, task.getRunnable());
|
||||||
|
this.expression = trigger.getExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExpression() {
|
||||||
|
return this.expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A description of a {@link Task Task's} {@link Runnable}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public static final class RunnableDescription {
|
||||||
|
|
||||||
|
private final String target;
|
||||||
|
|
||||||
|
private RunnableDescription(Runnable runnable) {
|
||||||
|
if (runnable instanceof ScheduledMethodRunnable) {
|
||||||
|
Method method = ((ScheduledMethodRunnable) runnable).getMethod();
|
||||||
|
this.target = method.getDeclaringClass().getName() + "."
|
||||||
|
+ method.getName();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.target = runnable.getClass().getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTarget() {
|
||||||
|
return this.target;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum TaskType {
|
||||||
|
|
||||||
|
CRON, FIXED_DELAY, FIXED_RATE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.actuate.scheduling;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.CronTaskDescription;
|
||||||
|
import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.FixedDelayTaskDescription;
|
||||||
|
import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.FixedRateTaskDescription;
|
||||||
|
import org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.ScheduledTasksReport;
|
||||||
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTaskHolder;
|
||||||
|
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||||
|
import org.springframework.scheduling.support.CronTrigger;
|
||||||
|
import org.springframework.scheduling.support.PeriodicTrigger;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link ScheduledTasksEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class ScheduledTasksEndpointTests {
|
||||||
|
|
||||||
|
private final ApplicationContextRunner runner = new ApplicationContextRunner()
|
||||||
|
.withUserConfiguration(BaseConfiguration.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cronScheduledMethodIsReported() {
|
||||||
|
run(CronScheduledMethod.class, (tasks) -> {
|
||||||
|
assertThat(tasks.getFixedDelay()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedRate()).isEmpty();
|
||||||
|
assertThat(tasks.getCron()).hasSize(1);
|
||||||
|
CronTaskDescription description = (CronTaskDescription) tasks.getCron()
|
||||||
|
.get(0);
|
||||||
|
assertThat(description.getExpression()).isEqualTo("0 0 0/3 1/1 * ?");
|
||||||
|
assertThat(description.getRunnable().getTarget())
|
||||||
|
.isEqualTo(CronScheduledMethod.class.getName() + ".cron");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cronTriggerIsReported() {
|
||||||
|
run(CronTriggerTask.class, (tasks) -> {
|
||||||
|
assertThat(tasks.getFixedRate()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedDelay()).isEmpty();
|
||||||
|
assertThat(tasks.getCron()).hasSize(1);
|
||||||
|
CronTaskDescription description = (CronTaskDescription) tasks.getCron()
|
||||||
|
.get(0);
|
||||||
|
assertThat(description.getExpression()).isEqualTo("0 0 0/6 1/1 * ?");
|
||||||
|
assertThat(description.getRunnable().getTarget())
|
||||||
|
.isEqualTo(CronTriggerRunnable.class.getName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fixedDelayScheduledMethodIsReported() {
|
||||||
|
run(FixedDelayScheduledMethod.class, (tasks) -> {
|
||||||
|
assertThat(tasks.getCron()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedRate()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedDelay()).hasSize(1);
|
||||||
|
FixedDelayTaskDescription description = (FixedDelayTaskDescription) tasks
|
||||||
|
.getFixedDelay().get(0);
|
||||||
|
assertThat(description.getInitialDelay()).isEqualTo(2);
|
||||||
|
assertThat(description.getInterval()).isEqualTo(1);
|
||||||
|
assertThat(description.getRunnable().getTarget())
|
||||||
|
.isEqualTo(FixedDelayScheduledMethod.class.getName() + ".fixedDelay");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fixedDelayTriggerIsReported() {
|
||||||
|
run(FixedDelayTriggerTask.class, (tasks) -> {
|
||||||
|
assertThat(tasks.getCron()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedRate()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedDelay()).hasSize(1);
|
||||||
|
FixedDelayTaskDescription description = (FixedDelayTaskDescription) tasks
|
||||||
|
.getFixedDelay().get(0);
|
||||||
|
assertThat(description.getInitialDelay()).isEqualTo(2000);
|
||||||
|
assertThat(description.getInterval()).isEqualTo(1000);
|
||||||
|
assertThat(description.getRunnable().getTarget())
|
||||||
|
.isEqualTo(FixedDelayTriggerRunnable.class.getName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fixedRateScheduledMethodIsReported() {
|
||||||
|
run(FixedRateScheduledMethod.class, (tasks) -> {
|
||||||
|
assertThat(tasks.getCron()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedDelay()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedRate()).hasSize(1);
|
||||||
|
FixedRateTaskDescription description = (FixedRateTaskDescription) tasks
|
||||||
|
.getFixedRate().get(0);
|
||||||
|
assertThat(description.getInitialDelay()).isEqualTo(4);
|
||||||
|
assertThat(description.getInterval()).isEqualTo(3);
|
||||||
|
assertThat(description.getRunnable().getTarget())
|
||||||
|
.isEqualTo(FixedRateScheduledMethod.class.getName() + ".fixedRate");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fixedRateTriggerIsReported() {
|
||||||
|
run(FixedRateTriggerTask.class, (tasks) -> {
|
||||||
|
assertThat(tasks.getCron()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedDelay()).isEmpty();
|
||||||
|
assertThat(tasks.getFixedRate()).hasSize(1);
|
||||||
|
FixedRateTaskDescription description = (FixedRateTaskDescription) tasks
|
||||||
|
.getFixedRate().get(0);
|
||||||
|
assertThat(description.getInitialDelay()).isEqualTo(3000);
|
||||||
|
assertThat(description.getInterval()).isEqualTo(2000);
|
||||||
|
assertThat(description.getRunnable().getTarget())
|
||||||
|
.isEqualTo(FixedRateTriggerRunnable.class.getName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void run(Class<?> configuration, Consumer<ScheduledTasksReport> consumer) {
|
||||||
|
this.runner.withUserConfiguration(configuration).run((context) -> consumer
|
||||||
|
.accept(context.getBean(ScheduledTasksEndpoint.class).scheduledTasks()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableScheduling
|
||||||
|
private static class BaseConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ScheduledTasksEndpoint endpoint(
|
||||||
|
Collection<ScheduledTaskHolder> scheduledTaskHolders) {
|
||||||
|
return new ScheduledTasksEndpoint(scheduledTaskHolders);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FixedDelayScheduledMethod {
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 1, initialDelay = 2)
|
||||||
|
public void fixedDelay() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FixedRateScheduledMethod {
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 3, initialDelay = 4)
|
||||||
|
public void fixedRate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CronScheduledMethod {
|
||||||
|
|
||||||
|
@Scheduled(cron = "0 0 0/3 1/1 * ?")
|
||||||
|
public void cron() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FixedDelayTriggerTask implements SchedulingConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||||
|
PeriodicTrigger trigger = new PeriodicTrigger(1, TimeUnit.SECONDS);
|
||||||
|
trigger.setInitialDelay(2);
|
||||||
|
taskRegistrar.addTriggerTask(new FixedDelayTriggerRunnable(), trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FixedRateTriggerTask implements SchedulingConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||||
|
PeriodicTrigger trigger = new PeriodicTrigger(2, TimeUnit.SECONDS);
|
||||||
|
trigger.setInitialDelay(3);
|
||||||
|
trigger.setFixedRate(true);
|
||||||
|
taskRegistrar.addTriggerTask(new FixedRateTriggerRunnable(), trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CronTriggerTask implements SchedulingConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||||
|
taskRegistrar.addTriggerTask(new CronTriggerRunnable(),
|
||||||
|
new CronTrigger("0 0 0/6 1/1 * ?"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CronTriggerRunnable implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FixedDelayTriggerRunnable implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FixedRateTriggerRunnable implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1181,6 +1181,13 @@ content into your application; rather pick only the properties that you need.
|
||||||
endpoints.prometheus.web.enabled= # Expose the metrics endpoint as a Web endpoint.
|
endpoints.prometheus.web.enabled= # Expose the metrics endpoint as a Web endpoint.
|
||||||
endpoints.prometheus.web.path=prometheus # Path of the prometheus endpoint.
|
endpoints.prometheus.web.path=prometheus # Path of the prometheus endpoint.
|
||||||
|
|
||||||
|
# SCHEDULED TASKS ENDPOINT ({sc-spring-boot-actuator}/scheduling/ScheduledTasksEndpoint.{sc-ext}[ScheduledTasksEndpoint])
|
||||||
|
endpoints.scheduledtasks.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
|
||||||
|
endpoints.scheduledtasks.enabled= # Enable the scheduled tasks endpoint.
|
||||||
|
endpoints.scheduledtasks.jmx.enabled= # Expose the scheduled tasks endpoint as a JMX MBean.
|
||||||
|
endpoints.scheduledtasks.web.enabled= # Expose the scheduled tasks endpoint as a Web endpoint.
|
||||||
|
endpoints.scheduledtasks.web.path=sessions # Path of the scheduled tasks endpoint.
|
||||||
|
|
||||||
# SESSIONS ENDPOINT ({sc-spring-boot-actuator}/session/SessionsEndpoint.{sc-ext}[SessionsEndpoint])
|
# SESSIONS ENDPOINT ({sc-spring-boot-actuator}/session/SessionsEndpoint.{sc-ext}[SessionsEndpoint])
|
||||||
endpoints.sessions.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
|
endpoints.sessions.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
|
||||||
endpoints.sessions.enabled= # Enable the sessions endpoint.
|
endpoints.sessions.enabled= # Enable the sessions endpoint.
|
||||||
|
|
|
@ -105,6 +105,9 @@ The following technology-agnostic endpoints are available:
|
||||||
|`mappings`
|
|`mappings`
|
||||||
|Displays a collated list of all `@RequestMapping` paths.
|
|Displays a collated list of all `@RequestMapping` paths.
|
||||||
|
|
||||||
|
|`scheduledtasks`
|
||||||
|
|Displays the scheduled tasks in your application.
|
||||||
|
|
||||||
|`sessions`
|
|`sessions`
|
||||||
|Allows retrieval and deletion of user sessions from a Spring Session-backed session
|
|Allows retrieval and deletion of user sessions from a Spring Session-backed session
|
||||||
store. Not available when using Spring Session's support for reactive web applications.
|
store. Not available when using Spring Session's support for reactive web applications.
|
||||||
|
|
Loading…
Reference in New Issue