TSK-1989: integrate execution of jobs in taskana core (#2087)
Co-authored-by: Mustapha Zorgati <15628173+mustaphazorgati@users.noreply.github.com>
This commit is contained in:
parent
4a42a35a21
commit
f64e38eb27
|
@ -52,9 +52,10 @@ public class DbSchemaCreator {
|
||||||
/**
|
/**
|
||||||
* Run all db scripts.
|
* Run all db scripts.
|
||||||
*
|
*
|
||||||
|
* @return true when schema was created, false when no schema created because already existing
|
||||||
* @throws SQLException will be thrown if there will be some incorrect SQL statements invoked.
|
* @throws SQLException will be thrown if there will be some incorrect SQL statements invoked.
|
||||||
*/
|
*/
|
||||||
public void run() throws SQLException {
|
public boolean run() throws SQLException {
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
|
@ -72,6 +73,7 @@ public class DbSchemaCreator {
|
||||||
BufferedReader reader =
|
BufferedReader reader =
|
||||||
new BufferedReader(new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8));
|
new BufferedReader(new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8));
|
||||||
runner.runScript(getSqlSchemaNameParsed(reader));
|
runner.runScript(getSqlSchemaNameParsed(reader));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
@ -80,6 +82,7 @@ public class DbSchemaCreator {
|
||||||
if (!errorWriter.toString().trim().isEmpty()) {
|
if (!errorWriter.toString().trim().isEmpty()) {
|
||||||
LOGGER.error(errorWriter.toString());
|
LOGGER.error(errorWriter.toString());
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValidSchemaVersion(String expectedMinVersion) {
|
public boolean isValidSchemaVersion(String expectedMinVersion) {
|
||||||
|
|
|
@ -45,12 +45,14 @@ public class TaskanaConfigurationInitializer {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
PROPERTY_INITIALIZER_BY_CLASS.put(Integer.class, new IntegerPropertyParser());
|
PROPERTY_INITIALIZER_BY_CLASS.put(Integer.class, new IntegerPropertyParser());
|
||||||
|
PROPERTY_INITIALIZER_BY_CLASS.put(Long.class, new LongPropertyParser());
|
||||||
PROPERTY_INITIALIZER_BY_CLASS.put(Boolean.class, new BooleanPropertyParser());
|
PROPERTY_INITIALIZER_BY_CLASS.put(Boolean.class, new BooleanPropertyParser());
|
||||||
PROPERTY_INITIALIZER_BY_CLASS.put(String.class, new StringPropertyParser());
|
PROPERTY_INITIALIZER_BY_CLASS.put(String.class, new StringPropertyParser());
|
||||||
PROPERTY_INITIALIZER_BY_CLASS.put(Duration.class, new DurationPropertyParser());
|
PROPERTY_INITIALIZER_BY_CLASS.put(Duration.class, new DurationPropertyParser());
|
||||||
PROPERTY_INITIALIZER_BY_CLASS.put(Instant.class, new InstantPropertyParser());
|
PROPERTY_INITIALIZER_BY_CLASS.put(Instant.class, new InstantPropertyParser());
|
||||||
PROPERTY_INITIALIZER_BY_CLASS.put(List.class, new ListPropertyParser());
|
PROPERTY_INITIALIZER_BY_CLASS.put(List.class, new ListPropertyParser());
|
||||||
PROPERTY_INITIALIZER_BY_CLASS.put(Map.class, new MapPropertyParser());
|
PROPERTY_INITIALIZER_BY_CLASS.put(Map.class, new MapPropertyParser());
|
||||||
|
PROPERTY_INITIALIZER_BY_CLASS.put(Enum.class, new EnumPropertyParser());
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskanaConfigurationInitializer() {
|
private TaskanaConfigurationInitializer() {
|
||||||
|
@ -65,12 +67,15 @@ public class TaskanaConfigurationInitializer {
|
||||||
.ifPresent(
|
.ifPresent(
|
||||||
taskanaProperty -> {
|
taskanaProperty -> {
|
||||||
Class<?> type = ReflectionUtil.wrap(field.getType());
|
Class<?> type = ReflectionUtil.wrap(field.getType());
|
||||||
PropertyParser<?> propertyParser =
|
PropertyParser<?> propertyParser;
|
||||||
Optional.ofNullable(PROPERTY_INITIALIZER_BY_CLASS.get(type))
|
if (type.isEnum()) {
|
||||||
.orElseThrow(
|
propertyParser = PROPERTY_INITIALIZER_BY_CLASS.get(Enum.class);
|
||||||
() ->
|
} else {
|
||||||
new SystemException(
|
propertyParser = PROPERTY_INITIALIZER_BY_CLASS.get(type);
|
||||||
String.format("Unknown configuration type '%s'", type)));
|
}
|
||||||
|
if (propertyParser == null) {
|
||||||
|
throw new SystemException(String.format("Unknown configuration type '%s'", type));
|
||||||
|
}
|
||||||
propertyParser
|
propertyParser
|
||||||
.initialize(props, separator, field, taskanaProperty)
|
.initialize(props, separator, field, taskanaProperty)
|
||||||
.ifPresent(value -> setFieldValue(instance, field, value));
|
.ifPresent(value -> setFieldValue(instance, field, value));
|
||||||
|
@ -275,7 +280,7 @@ public class TaskanaConfigurationInitializer {
|
||||||
String separator,
|
String separator,
|
||||||
Field field,
|
Field field,
|
||||||
TaskanaProperty taskanaProperty) {
|
TaskanaProperty taskanaProperty) {
|
||||||
if (!List.class.isAssignableFrom(field.getType())) {
|
if (!List.class.isAssignableFrom(ReflectionUtil.wrap(field.getType()))) {
|
||||||
throw new SystemException(
|
throw new SystemException(
|
||||||
String.format(
|
String.format(
|
||||||
"Cannot initialize field '%s' because field type '%s' is not a List",
|
"Cannot initialize field '%s' because field type '%s' is not a List",
|
||||||
|
@ -332,6 +337,12 @@ public class TaskanaConfigurationInitializer {
|
||||||
String separator,
|
String separator,
|
||||||
Field field,
|
Field field,
|
||||||
TaskanaProperty taskanaProperty) {
|
TaskanaProperty taskanaProperty) {
|
||||||
|
if (!Instant.class.isAssignableFrom(ReflectionUtil.wrap(field.getType()))) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Cannot initialize field '%s' because field type '%s' is not an Instant",
|
||||||
|
field, field.getType()));
|
||||||
|
}
|
||||||
return parseProperty(properties, taskanaProperty.value(), Instant::parse);
|
return parseProperty(properties, taskanaProperty.value(), Instant::parse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,6 +354,12 @@ public class TaskanaConfigurationInitializer {
|
||||||
String separator,
|
String separator,
|
||||||
Field field,
|
Field field,
|
||||||
TaskanaProperty taskanaProperty) {
|
TaskanaProperty taskanaProperty) {
|
||||||
|
if (!Duration.class.isAssignableFrom(ReflectionUtil.wrap(field.getType()))) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Cannot initialize field '%s' because field type '%s' is not a Duration",
|
||||||
|
field, field.getType()));
|
||||||
|
}
|
||||||
return parseProperty(properties, taskanaProperty.value(), Duration::parse);
|
return parseProperty(properties, taskanaProperty.value(), Duration::parse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -354,6 +371,12 @@ public class TaskanaConfigurationInitializer {
|
||||||
String separator,
|
String separator,
|
||||||
Field field,
|
Field field,
|
||||||
TaskanaProperty taskanaProperty) {
|
TaskanaProperty taskanaProperty) {
|
||||||
|
if (!String.class.isAssignableFrom(ReflectionUtil.wrap(field.getType()))) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Cannot initialize field '%s' because field type '%s' is not a String",
|
||||||
|
field, field.getType()));
|
||||||
|
}
|
||||||
return parseProperty(properties, taskanaProperty.value(), String::new);
|
return parseProperty(properties, taskanaProperty.value(), String::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,10 +388,33 @@ public class TaskanaConfigurationInitializer {
|
||||||
String separator,
|
String separator,
|
||||||
Field field,
|
Field field,
|
||||||
TaskanaProperty taskanaProperty) {
|
TaskanaProperty taskanaProperty) {
|
||||||
|
if (!Integer.class.isAssignableFrom(ReflectionUtil.wrap(field.getType()))) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Cannot initialize field '%s' because field type '%s' is not an Integer",
|
||||||
|
field, field.getType()));
|
||||||
|
}
|
||||||
return parseProperty(properties, taskanaProperty.value(), Integer::parseInt);
|
return parseProperty(properties, taskanaProperty.value(), Integer::parseInt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class LongPropertyParser implements PropertyParser<Long> {
|
||||||
|
@Override
|
||||||
|
public Optional<Long> initialize(
|
||||||
|
Map<String, String> properties,
|
||||||
|
String separator,
|
||||||
|
Field field,
|
||||||
|
TaskanaProperty taskanaProperty) {
|
||||||
|
if (!Long.class.isAssignableFrom(ReflectionUtil.wrap(field.getType()))) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Cannot initialize field '%s' because field type '%s' is not a Long",
|
||||||
|
field, field.getType()));
|
||||||
|
}
|
||||||
|
return parseProperty(properties, taskanaProperty.value(), Long::parseLong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class BooleanPropertyParser implements PropertyParser<Boolean> {
|
static class BooleanPropertyParser implements PropertyParser<Boolean> {
|
||||||
@Override
|
@Override
|
||||||
public Optional<Boolean> initialize(
|
public Optional<Boolean> initialize(
|
||||||
|
@ -376,7 +422,48 @@ public class TaskanaConfigurationInitializer {
|
||||||
String separator,
|
String separator,
|
||||||
Field field,
|
Field field,
|
||||||
TaskanaProperty taskanaProperty) {
|
TaskanaProperty taskanaProperty) {
|
||||||
|
if (!Boolean.class.isAssignableFrom(ReflectionUtil.wrap(field.getType()))) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Cannot initialize field '%s' because field type '%s' is not a Boolean",
|
||||||
|
field, field.getType()));
|
||||||
|
}
|
||||||
return parseProperty(properties, taskanaProperty.value(), Boolean::parseBoolean);
|
return parseProperty(properties, taskanaProperty.value(), Boolean::parseBoolean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class EnumPropertyParser implements PropertyParser<Enum<?>> {
|
||||||
|
@Override
|
||||||
|
public Optional<Enum<?>> initialize(
|
||||||
|
Map<String, String> properties,
|
||||||
|
String separator,
|
||||||
|
Field field,
|
||||||
|
TaskanaProperty taskanaProperty) {
|
||||||
|
if (!field.getType().isEnum()) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Cannot initialize field '%s' because field type '%s' is not an Enum",
|
||||||
|
field, field.getType()));
|
||||||
|
}
|
||||||
|
return parseProperty(
|
||||||
|
properties,
|
||||||
|
taskanaProperty.value(),
|
||||||
|
string -> {
|
||||||
|
Map<String, ?> enumConstantsByLowerCasedName =
|
||||||
|
Arrays.stream(field.getType().getEnumConstants())
|
||||||
|
.collect(
|
||||||
|
Collectors.toMap(e -> e.toString().toLowerCase(), Function.identity()));
|
||||||
|
Object o = enumConstantsByLowerCasedName.get(string.toLowerCase());
|
||||||
|
if (o == null) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Invalid property value '%s': Valid values are '%s' or '%s",
|
||||||
|
string,
|
||||||
|
enumConstantsByLowerCasedName.keySet(),
|
||||||
|
Arrays.toString(field.getType().getEnumConstants())));
|
||||||
|
}
|
||||||
|
return (Enum<?>) o;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import pro.taskana.common.api.TimeInterval;
|
||||||
import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
||||||
import pro.taskana.common.api.exceptions.MismatchedRoleException;
|
import pro.taskana.common.api.exceptions.MismatchedRoleException;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
|
||||||
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
import pro.taskana.common.internal.util.CollectionUtil;
|
import pro.taskana.common.internal.util.CollectionUtil;
|
||||||
|
@ -127,19 +126,6 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the HistoryCleanupJob schedule. <br>
|
|
||||||
* All scheduled cleanup jobs are cancelled/deleted and a new one is scheduled.
|
|
||||||
*
|
|
||||||
* @param taskanaEngine the TASKANA engine.
|
|
||||||
*/
|
|
||||||
public static void initializeSchedule(TaskanaEngine taskanaEngine) {
|
|
||||||
JobServiceImpl jobService = (JobServiceImpl) taskanaEngine.getJobService();
|
|
||||||
HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null);
|
|
||||||
jobService.deleteJobs(job.getType());
|
|
||||||
job.scheduleNextJob();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getType() {
|
protected String getType() {
|
||||||
return HistoryCleanupJob.class.getName();
|
return HistoryCleanupJob.class.getName();
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.junit.jupiter.api.function.ThrowingConsumer;
|
||||||
import pro.taskana.TaskanaConfiguration;
|
import pro.taskana.TaskanaConfiguration;
|
||||||
import pro.taskana.classification.internal.jobs.ClassificationChangedJob;
|
import pro.taskana.classification.internal.jobs.ClassificationChangedJob;
|
||||||
import pro.taskana.common.api.ScheduledJob;
|
import pro.taskana.common.api.ScheduledJob;
|
||||||
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.internal.util.Pair;
|
import pro.taskana.common.internal.util.Pair;
|
||||||
import pro.taskana.common.test.config.DataSourceGenerator;
|
import pro.taskana.common.test.config.DataSourceGenerator;
|
||||||
import pro.taskana.common.test.security.JaasExtension;
|
import pro.taskana.common.test.security.JaasExtension;
|
||||||
|
@ -453,7 +454,7 @@ class HistoryCleanupJobAccTest extends AbstractAccTest {
|
||||||
scheduledJob -> scheduledJob.getType().equals(HistoryCleanupJob.class.getName()))
|
scheduledJob -> scheduledJob.getType().equals(HistoryCleanupJob.class.getName()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
HistoryCleanupJob.initializeSchedule(taskanaEngine);
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, HistoryCleanupJob.class);
|
||||||
|
|
||||||
jobsToRun = getJobMapper().findJobsToRun(Instant.now());
|
jobsToRun = getJobMapper().findJobsToRun(Instant.now());
|
||||||
|
|
||||||
|
|
|
@ -25,4 +25,19 @@ taskana.workingtime.schedule.TUESDAY=00:00-00:00
|
||||||
taskana.workingtime.schedule.WEDNESDAY=00:00-00:00
|
taskana.workingtime.schedule.WEDNESDAY=00:00-00:00
|
||||||
taskana.workingtime.schedule.THURSDAY=00:00-00:00
|
taskana.workingtime.schedule.THURSDAY=00:00-00:00
|
||||||
taskana.workingtime.schedule.FRIDAY=00:00-00:00
|
taskana.workingtime.schedule.FRIDAY=00:00-00:00
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=false
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=true
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
datasource.jndi=java:jboss/datasources/TestDS
|
datasource.jndi=java:jboss/datasources/TestDS
|
||||||
taskana.domains=CDIDOMAIN
|
taskana.domains=CDIDOMAIN
|
||||||
taskana.classification.types=T1
|
taskana.classification.types=T1
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=true
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=1
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=false
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
|
@ -68,6 +68,7 @@ import pro.taskana.common.api.exceptions.TaskanaRuntimeException;
|
||||||
import pro.taskana.common.internal.InternalTaskanaEngine;
|
import pro.taskana.common.internal.InternalTaskanaEngine;
|
||||||
import pro.taskana.common.internal.Interval;
|
import pro.taskana.common.internal.Interval;
|
||||||
import pro.taskana.common.internal.TaskanaEngineImpl;
|
import pro.taskana.common.internal.TaskanaEngineImpl;
|
||||||
|
import pro.taskana.common.internal.jobs.JobScheduler;
|
||||||
import pro.taskana.common.internal.logging.LoggingAspect;
|
import pro.taskana.common.internal.logging.LoggingAspect;
|
||||||
import pro.taskana.common.internal.util.MapCreator;
|
import pro.taskana.common.internal.util.MapCreator;
|
||||||
import pro.taskana.common.internal.workingtime.HolidaySchedule;
|
import pro.taskana.common.internal.workingtime.HolidaySchedule;
|
||||||
|
@ -329,6 +330,8 @@ class ArchitectureTest {
|
||||||
.areNotAssignableTo(TaskanaEngine.class)
|
.areNotAssignableTo(TaskanaEngine.class)
|
||||||
.and()
|
.and()
|
||||||
.areNotAssignableTo(InternalTaskanaEngine.class)
|
.areNotAssignableTo(InternalTaskanaEngine.class)
|
||||||
|
.and()
|
||||||
|
.areNotAssignableTo(JobScheduler.class)
|
||||||
.should()
|
.should()
|
||||||
.onlyDependOnClassesThat()
|
.onlyDependOnClassesThat()
|
||||||
.resideOutsideOfPackage(rootPackage + "..")
|
.resideOutsideOfPackage(rootPackage + "..")
|
||||||
|
|
|
@ -4,13 +4,16 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.time.DayOfWeek;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.LocalTime;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.junit.jupiter.api.DynamicTest;
|
import org.junit.jupiter.api.DynamicTest;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -20,6 +23,7 @@ import org.junit.jupiter.api.function.ThrowingConsumer;
|
||||||
import pro.taskana.TaskanaConfiguration;
|
import pro.taskana.TaskanaConfiguration;
|
||||||
import pro.taskana.TaskanaConfiguration.Builder;
|
import pro.taskana.TaskanaConfiguration.Builder;
|
||||||
import pro.taskana.common.api.CustomHoliday;
|
import pro.taskana.common.api.CustomHoliday;
|
||||||
|
import pro.taskana.common.api.LocalTimeInterval;
|
||||||
import pro.taskana.common.api.TaskanaRole;
|
import pro.taskana.common.api.TaskanaRole;
|
||||||
import pro.taskana.common.internal.util.ReflectionUtil;
|
import pro.taskana.common.internal.util.ReflectionUtil;
|
||||||
import pro.taskana.testapi.extensions.TestContainerExtension;
|
import pro.taskana.testapi.extensions.TestContainerExtension;
|
||||||
|
@ -101,8 +105,14 @@ class TaskanaConfigurationTest {
|
||||||
Duration expectedUserRefreshJobRunEvery = Duration.ofDays(5);
|
Duration expectedUserRefreshJobRunEvery = Duration.ofDays(5);
|
||||||
List<WorkbasketPermission> expectedMinimalPermissionsToAssignDomains =
|
List<WorkbasketPermission> expectedMinimalPermissionsToAssignDomains =
|
||||||
List.of(WorkbasketPermission.CUSTOM_2);
|
List.of(WorkbasketPermission.CUSTOM_2);
|
||||||
|
long expectedJobSchedulerInitialStartDelay = 15;
|
||||||
|
long expectedJobSchedulerPeriod = 10;
|
||||||
|
TimeUnit expectedJobSchedulerPeriodTimeUnit = TimeUnit.DAYS;
|
||||||
|
List<String> expectedJobSchedulerCustomJobs = List.of("Job_A", "Job_B");
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
Map<DayOfWeek, Set<LocalTimeInterval>> expectedWorkingTimeSchedule =
|
||||||
|
Map.of(DayOfWeek.MONDAY, Set.of(new LocalTimeInterval(LocalTime.MIN, LocalTime.NOON)));
|
||||||
TaskanaConfiguration configuration =
|
TaskanaConfiguration configuration =
|
||||||
new Builder(TestContainerExtension.createDataSourceForH2(), false, "TASKANA")
|
new Builder(TestContainerExtension.createDataSourceForH2(), false, "TASKANA")
|
||||||
.domains(expectedDomains)
|
.domains(expectedDomains)
|
||||||
|
@ -127,6 +137,17 @@ class TaskanaConfigurationTest {
|
||||||
.userRefreshJobRunEvery(expectedUserRefreshJobRunEvery)
|
.userRefreshJobRunEvery(expectedUserRefreshJobRunEvery)
|
||||||
.addAdditionalUserInfo(true)
|
.addAdditionalUserInfo(true)
|
||||||
.minimalPermissionsToAssignDomains(expectedMinimalPermissionsToAssignDomains)
|
.minimalPermissionsToAssignDomains(expectedMinimalPermissionsToAssignDomains)
|
||||||
|
.jobSchedulerEnabled(false)
|
||||||
|
.jobSchedulerInitialStartDelay(expectedJobSchedulerInitialStartDelay)
|
||||||
|
.jobSchedulerPeriod(expectedJobSchedulerPeriod)
|
||||||
|
.jobSchedulerPeriodTimeUnit(expectedJobSchedulerPeriodTimeUnit)
|
||||||
|
.jobSchedulerEnableTaskCleanupJob(false)
|
||||||
|
.jobSchedulerEnableTaskUpdatePriorityJob(false)
|
||||||
|
.jobSchedulerEnableWorkbasketCleanupJob(false)
|
||||||
|
.jobSchedulerEnableUserInfoRefreshJob(false)
|
||||||
|
.jobSchedulerEnableHistorieCleanupJob(false)
|
||||||
|
.jobSchedulerCustomJobs(expectedJobSchedulerCustomJobs)
|
||||||
|
.workingTimeSchedule(expectedWorkingTimeSchedule)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
|
@ -155,6 +176,19 @@ class TaskanaConfigurationTest {
|
||||||
assertThat(configuration.isAddAdditionalUserInfo()).isTrue();
|
assertThat(configuration.isAddAdditionalUserInfo()).isTrue();
|
||||||
assertThat(configuration.getMinimalPermissionsToAssignDomains())
|
assertThat(configuration.getMinimalPermissionsToAssignDomains())
|
||||||
.isEqualTo(expectedMinimalPermissionsToAssignDomains);
|
.isEqualTo(expectedMinimalPermissionsToAssignDomains);
|
||||||
|
assertThat(configuration.isJobSchedulerEnabled()).isFalse();
|
||||||
|
assertThat(configuration.getJobSchedulerInitialStartDelay())
|
||||||
|
.isEqualTo(expectedJobSchedulerInitialStartDelay);
|
||||||
|
assertThat(configuration.getJobSchedulerPeriod()).isEqualTo(expectedJobSchedulerPeriod);
|
||||||
|
assertThat(configuration.getJobSchedulerPeriodTimeUnit())
|
||||||
|
.isEqualTo(expectedJobSchedulerPeriodTimeUnit);
|
||||||
|
assertThat(configuration.isJobSchedulerEnableTaskCleanupJob()).isFalse();
|
||||||
|
assertThat(configuration.isJobSchedulerEnableTaskUpdatePriorityJob()).isFalse();
|
||||||
|
assertThat(configuration.isJobSchedulerEnableWorkbasketCleanupJob()).isFalse();
|
||||||
|
assertThat(configuration.isJobSchedulerEnableUserInfoRefreshJob()).isFalse();
|
||||||
|
assertThat(configuration.isJobSchedulerEnableHistorieCleanupJob()).isFalse();
|
||||||
|
assertThat(configuration.getJobSchedulerCustomJobs()).isEqualTo(expectedJobSchedulerCustomJobs);
|
||||||
|
assertThat(configuration.getWorkingTimeSchedule()).isEqualTo(expectedWorkingTimeSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -184,6 +218,19 @@ class TaskanaConfigurationTest {
|
||||||
.userRefreshJobRunEvery(Duration.ofDays(5))
|
.userRefreshJobRunEvery(Duration.ofDays(5))
|
||||||
.addAdditionalUserInfo(true)
|
.addAdditionalUserInfo(true)
|
||||||
.minimalPermissionsToAssignDomains(List.of(WorkbasketPermission.CUSTOM_2))
|
.minimalPermissionsToAssignDomains(List.of(WorkbasketPermission.CUSTOM_2))
|
||||||
|
.jobSchedulerEnabled(false)
|
||||||
|
.jobSchedulerInitialStartDelay(10)
|
||||||
|
.jobSchedulerPeriod(15)
|
||||||
|
.jobSchedulerPeriodTimeUnit(TimeUnit.DAYS)
|
||||||
|
.jobSchedulerEnableTaskCleanupJob(false)
|
||||||
|
.jobSchedulerEnableTaskUpdatePriorityJob(false)
|
||||||
|
.jobSchedulerEnableWorkbasketCleanupJob(false)
|
||||||
|
.jobSchedulerEnableUserInfoRefreshJob(false)
|
||||||
|
.jobSchedulerEnableHistorieCleanupJob(false)
|
||||||
|
.jobSchedulerCustomJobs(List.of("Job_A", "Job_B"))
|
||||||
|
.workingTimeSchedule(
|
||||||
|
Map.of(
|
||||||
|
DayOfWeek.MONDAY, Set.of(new LocalTimeInterval(LocalTime.MIN, LocalTime.NOON))))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
TaskanaConfiguration copyConfiguration = new Builder(configuration).build();
|
TaskanaConfiguration copyConfiguration = new Builder(configuration).build();
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package acceptance.common;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import pro.taskana.TaskanaConfiguration;
|
||||||
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
|
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
|
||||||
|
import pro.taskana.common.internal.configuration.DB;
|
||||||
|
import pro.taskana.common.internal.configuration.DbSchemaCreator;
|
||||||
|
import pro.taskana.testapi.OracleSchemaHelper;
|
||||||
|
import pro.taskana.testapi.extensions.TestContainerExtension;
|
||||||
|
|
||||||
|
class TaskanaEngineExplizitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_CreateTaskanaEnine_When_ExplizitModeIsActive() throws Exception {
|
||||||
|
|
||||||
|
String schemaName = TestContainerExtension.determineSchemaName();
|
||||||
|
if (DB.isOracle(TestContainerExtension.EXECUTION_DATABASE.dbProductId)) {
|
||||||
|
OracleSchemaHelper.initOracleSchema(TestContainerExtension.DATA_SOURCE, schemaName);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskanaConfiguration taskanaEngineConfiguration =
|
||||||
|
new TaskanaConfiguration.Builder(
|
||||||
|
TestContainerExtension.DATA_SOURCE, false, schemaName, true)
|
||||||
|
.initTaskanaProperties()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
TaskanaEngine.buildTaskanaEngine(taskanaEngineConfiguration, ConnectionManagementMode.EXPLICIT);
|
||||||
|
|
||||||
|
DbSchemaCreator dsc =
|
||||||
|
new DbSchemaCreator(
|
||||||
|
taskanaEngineConfiguration.getDatasource(), taskanaEngineConfiguration.getSchemaName());
|
||||||
|
assertThat(dsc.isValidSchemaVersion(TaskanaEngine.MINIMAL_TASKANA_SCHEMA_VERSION)).isTrue();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package acceptance.jobs;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import pro.taskana.common.internal.jobs.Clock;
|
||||||
|
|
||||||
|
public class FakeClock implements Clock {
|
||||||
|
|
||||||
|
List<ClockListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(ClockListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
listeners.forEach(ClockListener::timeElapsed);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
package acceptance.jobs;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestInstance;
|
||||||
|
import org.junit.jupiter.api.TestInstance.Lifecycle;
|
||||||
|
|
||||||
|
import pro.taskana.TaskanaConfiguration;
|
||||||
|
import pro.taskana.TaskanaConfiguration.Builder;
|
||||||
|
import pro.taskana.classification.api.ClassificationService;
|
||||||
|
import pro.taskana.classification.api.models.ClassificationSummary;
|
||||||
|
import pro.taskana.common.api.ScheduledJob;
|
||||||
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
|
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
|
||||||
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
|
import pro.taskana.common.internal.JobMapper;
|
||||||
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
|
import pro.taskana.common.internal.jobs.JobScheduler;
|
||||||
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
|
import pro.taskana.task.api.TaskService;
|
||||||
|
import pro.taskana.task.api.TaskState;
|
||||||
|
import pro.taskana.task.api.models.ObjectReference;
|
||||||
|
import pro.taskana.task.api.models.TaskSummary;
|
||||||
|
import pro.taskana.task.internal.jobs.TaskCleanupJob;
|
||||||
|
import pro.taskana.testapi.DefaultTestEntities;
|
||||||
|
import pro.taskana.testapi.TaskanaEngineConfigurationModifier;
|
||||||
|
import pro.taskana.testapi.TaskanaInject;
|
||||||
|
import pro.taskana.testapi.TaskanaIntegrationTest;
|
||||||
|
import pro.taskana.testapi.builder.TaskBuilder;
|
||||||
|
import pro.taskana.testapi.security.WithAccessId;
|
||||||
|
import pro.taskana.workbasket.api.WorkbasketService;
|
||||||
|
import pro.taskana.workbasket.api.models.WorkbasketSummary;
|
||||||
|
|
||||||
|
@TaskanaIntegrationTest
|
||||||
|
class JobSchedulerExecutionAccTest implements TaskanaEngineConfigurationModifier {
|
||||||
|
@TaskanaInject TaskanaConfiguration taskanaConfiguration;
|
||||||
|
@TaskanaInject TaskService taskService;
|
||||||
|
@TaskanaInject JobMapper jobMapper;
|
||||||
|
WorkbasketSummary workbasket;
|
||||||
|
ClassificationSummary classification;
|
||||||
|
ObjectReference primaryObjRef;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder modify(Builder taskanaEngineConfigurationBuilder) {
|
||||||
|
return taskanaEngineConfigurationBuilder
|
||||||
|
.jobSchedulerEnableTaskCleanupJob(true)
|
||||||
|
.cleanupJobFirstRun(Instant.now().minus(10, ChronoUnit.MILLIS))
|
||||||
|
.cleanupJobRunEvery(Duration.ofMillis(1))
|
||||||
|
.cleanupJobMinimumAge(Duration.ofMillis(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithAccessId(user = "businessadmin")
|
||||||
|
@BeforeEach
|
||||||
|
void setup(WorkbasketService workbasketService, ClassificationService classificationService)
|
||||||
|
throws Exception {
|
||||||
|
workbasket =
|
||||||
|
DefaultTestEntities.defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService);
|
||||||
|
classification =
|
||||||
|
DefaultTestEntities.defaultTestClassification()
|
||||||
|
.buildAndStoreAsSummary(classificationService);
|
||||||
|
primaryObjRef = DefaultTestEntities.defaultTestObjectReference().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithAccessId(user = "admin")
|
||||||
|
@Test
|
||||||
|
void should_ExecuteAJobSuccessfully() throws Exception {
|
||||||
|
Instant timeStampAnyJobIsOverdue = Instant.now().plus(10, ChronoUnit.DAYS);
|
||||||
|
TaskanaEngine taskanaEngine =
|
||||||
|
TaskanaEngine.buildTaskanaEngine(taskanaConfiguration, ConnectionManagementMode.EXPLICIT);
|
||||||
|
JobScheduler jobScheduler = new JobScheduler(taskanaEngine, new FakeClock());
|
||||||
|
TaskBuilder.newTask()
|
||||||
|
.workbasketSummary(workbasket)
|
||||||
|
.classificationSummary(classification)
|
||||||
|
.primaryObjRef(primaryObjRef)
|
||||||
|
.state(TaskState.COMPLETED)
|
||||||
|
.completed(Instant.now().minus(5, ChronoUnit.DAYS))
|
||||||
|
.buildAndStoreAsSummary(taskService);
|
||||||
|
final List<ScheduledJob> jobsToRun = jobMapper.findJobsToRun(timeStampAnyJobIsOverdue);
|
||||||
|
|
||||||
|
Thread.sleep(2); // to make sure that TaskCleanupJob is overdue
|
||||||
|
jobScheduler.start();
|
||||||
|
|
||||||
|
List<TaskSummary> existingTasks = taskService.createTaskQuery().list();
|
||||||
|
assertThat(existingTasks).isEmpty();
|
||||||
|
List<ScheduledJob> jobsToRunAfter = jobMapper.findJobsToRun(timeStampAnyJobIsOverdue);
|
||||||
|
assertThat(jobsToRunAfter).isNotEmpty().doesNotContainAnyElementsOf(jobsToRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AlwaysFailJob extends AbstractTaskanaJob {
|
||||||
|
|
||||||
|
public AlwaysFailJob(
|
||||||
|
TaskanaEngine taskanaEngine, TaskanaTransactionProvider txProvider, ScheduledJob job) {
|
||||||
|
super(taskanaEngine, txProvider, job, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getType() {
|
||||||
|
return AlwaysFailJob.class.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute() {
|
||||||
|
throw new SystemException("I always fail. Muahhahaa!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(Lifecycle.PER_CLASS)
|
||||||
|
class AJobFails implements TaskanaEngineConfigurationModifier {
|
||||||
|
|
||||||
|
@TaskanaInject TaskanaConfiguration taskanaConfiguration;
|
||||||
|
@TaskanaInject TaskService taskService;
|
||||||
|
@TaskanaInject JobMapper jobMapper;
|
||||||
|
WorkbasketSummary workbasket;
|
||||||
|
ClassificationSummary classification;
|
||||||
|
ObjectReference primaryObjRef;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder modify(Builder taskanaEngineConfigurationBuilder) {
|
||||||
|
return taskanaEngineConfigurationBuilder
|
||||||
|
.jobSchedulerEnableTaskCleanupJob(false)
|
||||||
|
.cleanupJobFirstRun(Instant.now().minus(10, ChronoUnit.MILLIS))
|
||||||
|
.cleanupJobRunEvery(Duration.ofMillis(1))
|
||||||
|
.cleanupJobMinimumAge(Duration.ofMillis(10))
|
||||||
|
.jobSchedulerCustomJobs(
|
||||||
|
List.of(AlwaysFailJob.class.getName(), TaskCleanupJob.class.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithAccessId(user = "businessadmin")
|
||||||
|
@BeforeEach
|
||||||
|
void setup(WorkbasketService workbasketService, ClassificationService classificationService)
|
||||||
|
throws Exception {
|
||||||
|
workbasket =
|
||||||
|
DefaultTestEntities.defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService);
|
||||||
|
classification =
|
||||||
|
DefaultTestEntities.defaultTestClassification()
|
||||||
|
.buildAndStoreAsSummary(classificationService);
|
||||||
|
primaryObjRef = DefaultTestEntities.defaultTestObjectReference().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithAccessId(user = "admin")
|
||||||
|
@Test
|
||||||
|
void should_ContinueExecutingJobs_When_ASingeJobFails() throws Exception {
|
||||||
|
Instant timeStampAnyJobIsOverdue = Instant.now().plus(10, ChronoUnit.DAYS);
|
||||||
|
TaskanaEngine taskanaEngine =
|
||||||
|
TaskanaEngine.buildTaskanaEngine(taskanaConfiguration, ConnectionManagementMode.EXPLICIT);
|
||||||
|
JobScheduler jobScheduler = new JobScheduler(taskanaEngine, new FakeClock());
|
||||||
|
TaskBuilder.newTask()
|
||||||
|
.workbasketSummary(workbasket)
|
||||||
|
.classificationSummary(classification)
|
||||||
|
.primaryObjRef(primaryObjRef)
|
||||||
|
.state(TaskState.COMPLETED)
|
||||||
|
.completed(Instant.now().minus(5, ChronoUnit.DAYS))
|
||||||
|
.buildAndStoreAsSummary(taskService);
|
||||||
|
final List<ScheduledJob> jobsToRun = jobMapper.findJobsToRun(timeStampAnyJobIsOverdue);
|
||||||
|
|
||||||
|
Thread.sleep(2); // to make sure that TaskCleanupJob is overdue
|
||||||
|
jobScheduler.start();
|
||||||
|
|
||||||
|
List<TaskSummary> existingTasks = taskService.createTaskQuery().list();
|
||||||
|
assertThat(existingTasks).isEmpty();
|
||||||
|
List<ScheduledJob> jobsToRunAfter = jobMapper.findJobsToRun(timeStampAnyJobIsOverdue);
|
||||||
|
assertThat(jobsToRunAfter).isNotEmpty().doesNotContainAnyElementsOf(jobsToRun);
|
||||||
|
assertThat(jobsToRunAfter)
|
||||||
|
.filteredOn(job -> AlwaysFailJob.class.getName().equals(job.getType()))
|
||||||
|
.extracting(ScheduledJob::getRetryCount)
|
||||||
|
.containsExactly(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package acceptance.jobs;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import pro.taskana.TaskanaConfiguration;
|
||||||
|
import pro.taskana.common.api.ScheduledJob;
|
||||||
|
import pro.taskana.common.internal.JobMapper;
|
||||||
|
import pro.taskana.task.internal.jobs.TaskCleanupJob;
|
||||||
|
import pro.taskana.task.internal.jobs.TaskUpdatePriorityJob;
|
||||||
|
import pro.taskana.testapi.TaskanaEngineConfigurationModifier;
|
||||||
|
import pro.taskana.testapi.TaskanaInject;
|
||||||
|
import pro.taskana.testapi.TaskanaIntegrationTest;
|
||||||
|
import pro.taskana.workbasket.internal.jobs.WorkbasketCleanupJob;
|
||||||
|
|
||||||
|
@TaskanaIntegrationTest
|
||||||
|
class JobSchedulerInitAccTest implements TaskanaEngineConfigurationModifier {
|
||||||
|
|
||||||
|
@TaskanaInject JobMapper jobMapper;
|
||||||
|
|
||||||
|
Instant firstRun = Instant.now().minus(2, ChronoUnit.MINUTES).truncatedTo(ChronoUnit.MILLIS);
|
||||||
|
Duration runEvery = Duration.ofMinutes(5);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskanaConfiguration.Builder modify(
|
||||||
|
TaskanaConfiguration.Builder taskanaEngineConfigurationBuilder) {
|
||||||
|
return taskanaEngineConfigurationBuilder
|
||||||
|
.cleanupJobRunEvery(runEvery)
|
||||||
|
.cleanupJobFirstRun(firstRun)
|
||||||
|
// config for TaskUpdatePriorityJob
|
||||||
|
.priorityJobActive(true)
|
||||||
|
.priorityJobRunEvery(runEvery)
|
||||||
|
.priorityJobFirstRun(firstRun)
|
||||||
|
.jobSchedulerEnabled(true)
|
||||||
|
.jobSchedulerInitialStartDelay(100)
|
||||||
|
.jobSchedulerPeriod(100)
|
||||||
|
.jobSchedulerPeriodTimeUnit(TimeUnit.SECONDS)
|
||||||
|
.jobSchedulerEnableTaskCleanupJob(true)
|
||||||
|
.jobSchedulerEnableTaskUpdatePriorityJob(true)
|
||||||
|
.jobSchedulerEnableWorkbasketCleanupJob(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_StartTheJobsImmediately_When_StartMethodIsCalled() throws Exception {
|
||||||
|
List<ScheduledJob> nextJobs = jobMapper.findJobsToRun(Instant.now().plus(runEvery));
|
||||||
|
assertThat(nextJobs).extracting(ScheduledJob::getDue).containsOnly(firstRun.plus(runEvery));
|
||||||
|
assertThat(nextJobs)
|
||||||
|
.extracting(ScheduledJob::getType)
|
||||||
|
.containsExactlyInAnyOrder(
|
||||||
|
TaskUpdatePriorityJob.class.getName(),
|
||||||
|
TaskCleanupJob.class.getName(),
|
||||||
|
WorkbasketCleanupJob.class.getName());
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,4 +18,18 @@ taskana.german.holidays.corpus-christi.enabled=false
|
||||||
taskana.history.deletion.on.task.deletion.enabled=true
|
taskana.history.deletion.on.task.deletion.enabled=true
|
||||||
taskana.validation.allowTimestampServiceLevelMismatch=false
|
taskana.validation.allowTimestampServiceLevelMismatch=false
|
||||||
taskana.query.includeLongName=false
|
taskana.query.includeLongName=false
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100000
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=false
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=false
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=false
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=false
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Map.Entry;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -65,6 +66,16 @@ public class TaskanaConfiguration {
|
||||||
// region custom configuration
|
// region custom configuration
|
||||||
private final Map<String, String> properties;
|
private final Map<String, String> properties;
|
||||||
private final Map<DayOfWeek, Set<LocalTimeInterval>> workingTimeSchedule;
|
private final Map<DayOfWeek, Set<LocalTimeInterval>> workingTimeSchedule;
|
||||||
|
private final boolean jobSchedulerEnabled;
|
||||||
|
private final long jobSchedulerInitialStartDelay;
|
||||||
|
private final long jobSchedulerPeriod;
|
||||||
|
private final TimeUnit jobSchedulerPeriodTimeUnit;
|
||||||
|
private final boolean jobSchedulerEnableTaskCleanupJob;
|
||||||
|
private final boolean jobSchedulerEnableTaskUpdatePriorityJob;
|
||||||
|
private final boolean jobSchedulerEnableWorkbasketCleanupJob;
|
||||||
|
private final boolean jobSchedulerEnableUserInfoRefreshJob;
|
||||||
|
private final boolean jobSchedulerEnableHistorieCleanupJob;
|
||||||
|
private final List<String> jobSchedulerCustomJobs;
|
||||||
|
|
||||||
@TaskanaProperty("taskana.domains")
|
@TaskanaProperty("taskana.domains")
|
||||||
private List<String> domains = new ArrayList<>();
|
private List<String> domains = new ArrayList<>();
|
||||||
|
@ -96,6 +107,7 @@ public class TaskanaConfiguration {
|
||||||
// TODO: validate this is positive
|
// TODO: validate this is positive
|
||||||
@TaskanaProperty("taskana.jobs.cleanup.runEvery")
|
@TaskanaProperty("taskana.jobs.cleanup.runEvery")
|
||||||
private Duration cleanupJobRunEvery = Duration.ofDays(1);
|
private Duration cleanupJobRunEvery = Duration.ofDays(1);
|
||||||
|
// endregion
|
||||||
// TODO: validate this is positive
|
// TODO: validate this is positive
|
||||||
@TaskanaProperty("taskana.jobs.cleanup.minimumAge")
|
@TaskanaProperty("taskana.jobs.cleanup.minimumAge")
|
||||||
private Duration cleanupJobMinimumAge = Duration.ofDays(14);
|
private Duration cleanupJobMinimumAge = Duration.ofDays(14);
|
||||||
|
@ -127,7 +139,6 @@ public class TaskanaConfiguration {
|
||||||
// TODO: make Set
|
// TODO: make Set
|
||||||
@TaskanaProperty("taskana.user.minimalPermissionsToAssignDomains")
|
@TaskanaProperty("taskana.user.minimalPermissionsToAssignDomains")
|
||||||
private List<WorkbasketPermission> minimalPermissionsToAssignDomains = new ArrayList<>();
|
private List<WorkbasketPermission> minimalPermissionsToAssignDomains = new ArrayList<>();
|
||||||
// endregion
|
|
||||||
|
|
||||||
protected TaskanaConfiguration(Builder builder) {
|
protected TaskanaConfiguration(Builder builder) {
|
||||||
this.dataSource = builder.dataSource;
|
this.dataSource = builder.dataSource;
|
||||||
|
@ -173,6 +184,16 @@ public class TaskanaConfiguration {
|
||||||
this.userRefreshJobFirstRun = builder.userRefreshJobFirstRun;
|
this.userRefreshJobFirstRun = builder.userRefreshJobFirstRun;
|
||||||
this.minimalPermissionsToAssignDomains =
|
this.minimalPermissionsToAssignDomains =
|
||||||
Collections.unmodifiableList(builder.minimalPermissionsToAssignDomains);
|
Collections.unmodifiableList(builder.minimalPermissionsToAssignDomains);
|
||||||
|
this.jobSchedulerEnabled = builder.jobSchedulerEnabled;
|
||||||
|
this.jobSchedulerInitialStartDelay = builder.jobSchedulerInitialStartDelay;
|
||||||
|
this.jobSchedulerPeriod = builder.jobSchedulerPeriod;
|
||||||
|
this.jobSchedulerPeriodTimeUnit = builder.jobSchedulerPeriodTimeUnit;
|
||||||
|
this.jobSchedulerEnableTaskCleanupJob = builder.jobSchedulerEnableTaskCleanupJob;
|
||||||
|
this.jobSchedulerEnableTaskUpdatePriorityJob = builder.jobSchedulerEnableTaskUpdatePriorityJob;
|
||||||
|
this.jobSchedulerEnableWorkbasketCleanupJob = builder.jobSchedulerEnableWorkbasketCleanupJob;
|
||||||
|
this.jobSchedulerEnableUserInfoRefreshJob = builder.jobSchedulerEnableUserInfoRefreshJob;
|
||||||
|
this.jobSchedulerEnableHistorieCleanupJob = builder.jobSchedulerEnableHistorieCleanupJob;
|
||||||
|
this.jobSchedulerCustomJobs = Collections.unmodifiableList(builder.jobSchedulerCustomJobs);
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
// TODO remove the reflection magic when introducing lombok toString magic :-)
|
// TODO remove the reflection magic when introducing lombok toString magic :-)
|
||||||
|
@ -332,6 +353,46 @@ public class TaskanaConfiguration {
|
||||||
return schemaName;
|
return schemaName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isJobSchedulerEnabled() {
|
||||||
|
return jobSchedulerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getJobSchedulerInitialStartDelay() {
|
||||||
|
return jobSchedulerInitialStartDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getJobSchedulerPeriod() {
|
||||||
|
return jobSchedulerPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeUnit getJobSchedulerPeriodTimeUnit() {
|
||||||
|
return jobSchedulerPeriodTimeUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isJobSchedulerEnableTaskCleanupJob() {
|
||||||
|
return jobSchedulerEnableTaskCleanupJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isJobSchedulerEnableTaskUpdatePriorityJob() {
|
||||||
|
return jobSchedulerEnableTaskUpdatePriorityJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isJobSchedulerEnableWorkbasketCleanupJob() {
|
||||||
|
return jobSchedulerEnableWorkbasketCleanupJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isJobSchedulerEnableUserInfoRefreshJob() {
|
||||||
|
return jobSchedulerEnableUserInfoRefreshJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isJobSchedulerEnableHistorieCleanupJob() {
|
||||||
|
return jobSchedulerEnableHistorieCleanupJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getJobSchedulerCustomJobs() {
|
||||||
|
return jobSchedulerCustomJobs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to determine whether all access ids (user Id and group ids) should be used in
|
* Helper method to determine whether all access ids (user Id and group ids) should be used in
|
||||||
* lower case.
|
* lower case.
|
||||||
|
@ -434,6 +495,36 @@ public class TaskanaConfiguration {
|
||||||
|
|
||||||
@TaskanaProperty("taskana.jobs.user.refresh.firstRunAt")
|
@TaskanaProperty("taskana.jobs.user.refresh.firstRunAt")
|
||||||
private Instant userRefreshJobFirstRun = Instant.parse("2018-01-01T23:00:00Z");
|
private Instant userRefreshJobFirstRun = Instant.parse("2018-01-01T23:00:00Z");
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.enabled")
|
||||||
|
private boolean jobSchedulerEnabled = true;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.initialstartdelay")
|
||||||
|
private long jobSchedulerInitialStartDelay = 100;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.period")
|
||||||
|
private long jobSchedulerPeriod = 12;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.periodtimeunit")
|
||||||
|
private TimeUnit jobSchedulerPeriodTimeUnit = TimeUnit.HOURS;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.enableTaskCleanupJob")
|
||||||
|
private boolean jobSchedulerEnableTaskCleanupJob = true;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.enableTaskUpdatePriorityJob")
|
||||||
|
private boolean jobSchedulerEnableTaskUpdatePriorityJob = true;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.enableWorkbasketCleanupJob")
|
||||||
|
private boolean jobSchedulerEnableWorkbasketCleanupJob = true;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.enableUserInfoRefreshJob")
|
||||||
|
private boolean jobSchedulerEnableUserInfoRefreshJob = true;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.enableHistorieCleanupJob")
|
||||||
|
private boolean jobSchedulerEnableHistorieCleanupJob = true;
|
||||||
|
|
||||||
|
@TaskanaProperty("taskana.jobscheduler.customJobs")
|
||||||
|
private List<String> jobSchedulerCustomJobs = new ArrayList<>();
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region user configuration
|
// region user configuration
|
||||||
|
@ -480,6 +571,17 @@ public class TaskanaConfiguration {
|
||||||
this.userRefreshJobRunEvery = tec.getUserRefreshJobRunEvery();
|
this.userRefreshJobRunEvery = tec.getUserRefreshJobRunEvery();
|
||||||
this.userRefreshJobFirstRun = tec.getUserRefreshJobFirstRun();
|
this.userRefreshJobFirstRun = tec.getUserRefreshJobFirstRun();
|
||||||
this.minimalPermissionsToAssignDomains = tec.getMinimalPermissionsToAssignDomains();
|
this.minimalPermissionsToAssignDomains = tec.getMinimalPermissionsToAssignDomains();
|
||||||
|
this.jobSchedulerEnabled = tec.isJobSchedulerEnabled();
|
||||||
|
this.jobSchedulerInitialStartDelay = tec.getJobSchedulerInitialStartDelay();
|
||||||
|
this.jobSchedulerPeriod = tec.getJobSchedulerPeriod();
|
||||||
|
this.jobSchedulerPeriodTimeUnit = tec.getJobSchedulerPeriodTimeUnit();
|
||||||
|
this.jobSchedulerEnableTaskCleanupJob = tec.isJobSchedulerEnableTaskCleanupJob();
|
||||||
|
this.jobSchedulerEnableTaskUpdatePriorityJob =
|
||||||
|
tec.isJobSchedulerEnableTaskUpdatePriorityJob();
|
||||||
|
this.jobSchedulerEnableWorkbasketCleanupJob = tec.isJobSchedulerEnableWorkbasketCleanupJob();
|
||||||
|
this.jobSchedulerEnableUserInfoRefreshJob = tec.isJobSchedulerEnableUserInfoRefreshJob();
|
||||||
|
this.jobSchedulerEnableHistorieCleanupJob = tec.isJobSchedulerEnableHistorieCleanupJob();
|
||||||
|
this.jobSchedulerCustomJobs = tec.getJobSchedulerCustomJobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder(DataSource dataSource, boolean useManagedTransactions, String schemaName) {
|
public Builder(DataSource dataSource, boolean useManagedTransactions, String schemaName) {
|
||||||
|
@ -649,6 +751,65 @@ public class TaskanaConfiguration {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerEnabled(boolean jobSchedulerEnabled) {
|
||||||
|
this.jobSchedulerEnabled = jobSchedulerEnabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerInitialStartDelay(long jobSchedulerInitialStartDelay) {
|
||||||
|
this.jobSchedulerInitialStartDelay = jobSchedulerInitialStartDelay;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerPeriod(long jobSchedulerPeriod) {
|
||||||
|
this.jobSchedulerPeriod = jobSchedulerPeriod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerPeriodTimeUnit(TimeUnit jobSchedulerPeriodTimeUnit) {
|
||||||
|
this.jobSchedulerPeriodTimeUnit = jobSchedulerPeriodTimeUnit;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerEnableTaskCleanupJob(boolean jobSchedulerEnableTaskCleanupJob) {
|
||||||
|
this.jobSchedulerEnableTaskCleanupJob = jobSchedulerEnableTaskCleanupJob;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerEnableTaskUpdatePriorityJob(
|
||||||
|
boolean jobSchedulerEnableTaskUpdatePriorityJob) {
|
||||||
|
this.jobSchedulerEnableTaskUpdatePriorityJob = jobSchedulerEnableTaskUpdatePriorityJob;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerEnableWorkbasketCleanupJob(
|
||||||
|
boolean jobSchedulerEnableWorkbasketCleanupJob) {
|
||||||
|
this.jobSchedulerEnableWorkbasketCleanupJob = jobSchedulerEnableWorkbasketCleanupJob;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerEnableUserInfoRefreshJob(
|
||||||
|
boolean jobSchedulerEnableUserInfoRefreshJob) {
|
||||||
|
this.jobSchedulerEnableUserInfoRefreshJob = jobSchedulerEnableUserInfoRefreshJob;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerEnableHistorieCleanupJob(
|
||||||
|
boolean jobSchedulerEnableHistorieCleanupJob) {
|
||||||
|
this.jobSchedulerEnableHistorieCleanupJob = jobSchedulerEnableHistorieCleanupJob;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder jobSchedulerCustomJobs(List<String> jobSchedulerCustomJobs) {
|
||||||
|
this.jobSchedulerCustomJobs = jobSchedulerCustomJobs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder workingTimeSchedule(Map<DayOfWeek, Set<LocalTimeInterval>> workingTimeSchedule) {
|
||||||
|
this.workingTimeSchedule = workingTimeSchedule;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TaskanaConfiguration build() {
|
public TaskanaConfiguration build() {
|
||||||
return new TaskanaConfiguration(this);
|
return new TaskanaConfiguration(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import pro.taskana.workbasket.api.WorkbasketService;
|
||||||
|
|
||||||
/** The TaskanaEngine represents an overall set of all needed services. */
|
/** The TaskanaEngine represents an overall set of all needed services. */
|
||||||
public interface TaskanaEngine {
|
public interface TaskanaEngine {
|
||||||
|
String MINIMAL_TASKANA_SCHEMA_VERSION = "5.2.0";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@linkplain TaskService} initialized with the current TaskanaEngine. {@linkplain
|
* Returns a {@linkplain TaskService} initialized with the current TaskanaEngine. {@linkplain
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package pro.taskana.common.internal;
|
package pro.taskana.common.internal;
|
||||||
|
|
||||||
|
import static pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode.EXPLICIT;
|
||||||
|
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
@ -43,6 +45,8 @@ import pro.taskana.common.api.security.CurrentUserContext;
|
||||||
import pro.taskana.common.api.security.UserPrincipal;
|
import pro.taskana.common.api.security.UserPrincipal;
|
||||||
import pro.taskana.common.internal.configuration.DB;
|
import pro.taskana.common.internal.configuration.DB;
|
||||||
import pro.taskana.common.internal.configuration.DbSchemaCreator;
|
import pro.taskana.common.internal.configuration.DbSchemaCreator;
|
||||||
|
import pro.taskana.common.internal.jobs.JobScheduler;
|
||||||
|
import pro.taskana.common.internal.jobs.RealClock;
|
||||||
import pro.taskana.common.internal.persistence.InstantTypeHandler;
|
import pro.taskana.common.internal.persistence.InstantTypeHandler;
|
||||||
import pro.taskana.common.internal.persistence.MapTypeHandler;
|
import pro.taskana.common.internal.persistence.MapTypeHandler;
|
||||||
import pro.taskana.common.internal.persistence.StringTypeHandler;
|
import pro.taskana.common.internal.persistence.StringTypeHandler;
|
||||||
|
@ -83,7 +87,6 @@ import pro.taskana.workbasket.internal.WorkbasketServiceImpl;
|
||||||
public class TaskanaEngineImpl implements TaskanaEngine {
|
public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
|
|
||||||
// must match the VERSION value in table
|
// must match the VERSION value in table
|
||||||
private static final String MINIMAL_TASKANA_SCHEMA_VERSION = "5.2.0";
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineImpl.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineImpl.class);
|
||||||
private static final SessionStack SESSION_STACK = new SessionStack();
|
private static final SessionStack SESSION_STACK = new SessionStack();
|
||||||
protected final TaskanaConfiguration taskanaEngineConfiguration;
|
protected final TaskanaConfiguration taskanaEngineConfiguration;
|
||||||
|
@ -114,8 +117,14 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
"initializing TASKANA with this configuration: {} and this mode: {}",
|
"initializing TASKANA with this configuration: {} and this mode: {}",
|
||||||
taskanaEngineConfiguration,
|
taskanaEngineConfiguration,
|
||||||
connectionManagementMode);
|
connectionManagementMode);
|
||||||
this.taskanaEngineConfiguration = taskanaEngineConfiguration;
|
if (connectionManagementMode == EXPLICIT) {
|
||||||
|
// at first we initialize Taskana DB with autocommit,
|
||||||
|
// at the end of constructor the mode is set
|
||||||
|
this.mode = ConnectionManagementMode.AUTOCOMMIT;
|
||||||
|
} else {
|
||||||
this.mode = connectionManagementMode;
|
this.mode = connectionManagementMode;
|
||||||
|
}
|
||||||
|
this.taskanaEngineConfiguration = taskanaEngineConfiguration;
|
||||||
internalTaskanaEngineImpl = new InternalTaskanaEngineImpl();
|
internalTaskanaEngineImpl = new InternalTaskanaEngineImpl();
|
||||||
HolidaySchedule holidaySchedule =
|
HolidaySchedule holidaySchedule =
|
||||||
new HolidaySchedule(
|
new HolidaySchedule(
|
||||||
|
@ -143,6 +152,24 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
afterRequestReviewManager = new AfterRequestReviewManager(this);
|
afterRequestReviewManager = new AfterRequestReviewManager(this);
|
||||||
beforeRequestChangesManager = new BeforeRequestChangesManager(this);
|
beforeRequestChangesManager = new BeforeRequestChangesManager(this);
|
||||||
afterRequestChangesManager = new AfterRequestChangesManager(this);
|
afterRequestChangesManager = new AfterRequestChangesManager(this);
|
||||||
|
|
||||||
|
if (this.taskanaEngineConfiguration.isJobSchedulerEnabled()) {
|
||||||
|
TaskanaConfiguration tec =
|
||||||
|
new TaskanaConfiguration.Builder(this.taskanaEngineConfiguration)
|
||||||
|
.jobSchedulerEnabled(false)
|
||||||
|
.build();
|
||||||
|
TaskanaEngine taskanaEngine = TaskanaEngine.buildTaskanaEngine(tec, EXPLICIT);
|
||||||
|
RealClock clock =
|
||||||
|
new RealClock(
|
||||||
|
this.taskanaEngineConfiguration.getJobSchedulerInitialStartDelay(),
|
||||||
|
this.taskanaEngineConfiguration.getJobSchedulerPeriod(),
|
||||||
|
this.taskanaEngineConfiguration.getJobSchedulerPeriodTimeUnit());
|
||||||
|
JobScheduler jobScheduler = new JobScheduler(taskanaEngine, clock);
|
||||||
|
jobScheduler.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't remove, to reset possible explicit mode
|
||||||
|
this.mode = connectionManagementMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TaskanaEngine createTaskanaEngine(
|
public static TaskanaEngine createTaskanaEngine(
|
||||||
|
@ -194,6 +221,25 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
sessionManager.getMapper(TaskMapper.class));
|
sessionManager.getMapper(TaskMapper.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Connection getConnection() {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setConnection(Connection connection) throws SQLException {
|
||||||
|
if (connection != null) {
|
||||||
|
this.connection = connection;
|
||||||
|
// disabling auto commit for passed connection in order to gain full control over the
|
||||||
|
// connection management
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
connection.setSchema(taskanaEngineConfiguration.getSchemaName());
|
||||||
|
mode = EXPLICIT;
|
||||||
|
sessionManager.startManagedSession(connection);
|
||||||
|
} else if (this.connection != null) {
|
||||||
|
closeConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This should be part of the InternalTaskanaEngine. Unfortunately the jobs don't have access to
|
// This should be part of the InternalTaskanaEngine. Unfortunately the jobs don't have access to
|
||||||
// that engine.
|
// that engine.
|
||||||
// Therefore, this getter exits and will be removed as soon as our jobs will be refactored.
|
// Therefore, this getter exits and will be removed as soon as our jobs will be refactored.
|
||||||
|
@ -234,9 +280,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setConnectionManagementMode(ConnectionManagementMode mode) {
|
public void setConnectionManagementMode(ConnectionManagementMode mode) {
|
||||||
if (this.mode == ConnectionManagementMode.EXPLICIT
|
if (this.mode == EXPLICIT && connection != null && mode != EXPLICIT) {
|
||||||
&& connection != null
|
|
||||||
&& mode != ConnectionManagementMode.EXPLICIT) {
|
|
||||||
if (sessionManager.isManagedSessionStarted()) {
|
if (sessionManager.isManagedSessionStarted()) {
|
||||||
sessionManager.close();
|
sessionManager.close();
|
||||||
}
|
}
|
||||||
|
@ -245,24 +289,9 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setConnection(Connection connection) throws SQLException {
|
|
||||||
if (connection != null) {
|
|
||||||
this.connection = connection;
|
|
||||||
// disabling auto commit for passed connection in order to gain full control over the
|
|
||||||
// connection management
|
|
||||||
connection.setAutoCommit(false);
|
|
||||||
connection.setSchema(taskanaEngineConfiguration.getSchemaName());
|
|
||||||
mode = ConnectionManagementMode.EXPLICIT;
|
|
||||||
sessionManager.startManagedSession(connection);
|
|
||||||
} else if (this.connection != null) {
|
|
||||||
closeConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeConnection() {
|
public void closeConnection() {
|
||||||
if (this.mode == ConnectionManagementMode.EXPLICIT) {
|
if (this.mode == EXPLICIT) {
|
||||||
this.connection = null;
|
this.connection = null;
|
||||||
if (sessionManager.isManagedSessionStarted()) {
|
if (sessionManager.isManagedSessionStarted()) {
|
||||||
sessionManager.close();
|
sessionManager.close();
|
||||||
|
@ -397,21 +426,24 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
return SqlSessionManager.newInstance(localSessionFactory);
|
return SqlSessionManager.newInstance(localSessionFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeDbSchema(TaskanaConfiguration taskanaEngineConfiguration)
|
private boolean initializeDbSchema(TaskanaConfiguration taskanaEngineConfiguration)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
DbSchemaCreator dbSchemaCreator =
|
DbSchemaCreator dbSchemaCreator =
|
||||||
new DbSchemaCreator(
|
new DbSchemaCreator(
|
||||||
taskanaEngineConfiguration.getDatasource(), taskanaEngineConfiguration.getSchemaName());
|
taskanaEngineConfiguration.getDatasource(), taskanaEngineConfiguration.getSchemaName());
|
||||||
dbSchemaCreator.run();
|
boolean schemaCreated = dbSchemaCreator.run();
|
||||||
|
|
||||||
|
if (!schemaCreated) {
|
||||||
if (!dbSchemaCreator.isValidSchemaVersion(MINIMAL_TASKANA_SCHEMA_VERSION)) {
|
if (!dbSchemaCreator.isValidSchemaVersion(MINIMAL_TASKANA_SCHEMA_VERSION)) {
|
||||||
throw new SystemException(
|
throw new SystemException(
|
||||||
"The Database Schema Version doesn't match the expected minimal version "
|
"The Database Schema Version doesn't match the expected minimal version "
|
||||||
+ MINIMAL_TASKANA_SCHEMA_VERSION);
|
+ MINIMAL_TASKANA_SCHEMA_VERSION);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
((ConfigurationServiceImpl) getConfigurationService())
|
((ConfigurationServiceImpl) getConfigurationService())
|
||||||
.checkSecureAccess(taskanaEngineConfiguration.isSecurityEnabled());
|
.checkSecureAccess(taskanaEngineConfiguration.isSecurityEnabled());
|
||||||
((ConfigurationServiceImpl) getConfigurationService()).setupDefaultCustomAttributes();
|
((ConfigurationServiceImpl) getConfigurationService()).setupDefaultCustomAttributes();
|
||||||
|
return schemaCreated;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -483,14 +515,14 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
+ "to the database. No schema has been created.",
|
+ "to the database. No schema has been created.",
|
||||||
e.getCause());
|
e.getCause());
|
||||||
}
|
}
|
||||||
if (mode != ConnectionManagementMode.EXPLICIT) {
|
if (mode != EXPLICIT) {
|
||||||
SESSION_STACK.pushSessionToStack(sessionManager);
|
SESSION_STACK.pushSessionToStack(sessionManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void returnConnection() {
|
public void returnConnection() {
|
||||||
if (mode != ConnectionManagementMode.EXPLICIT) {
|
if (mode != EXPLICIT) {
|
||||||
SESSION_STACK.popSessionFromStack();
|
SESSION_STACK.popSessionFromStack();
|
||||||
if (SESSION_STACK.getSessionStack().isEmpty()
|
if (SESSION_STACK.getSessionStack().isEmpty()
|
||||||
&& sessionManager != null
|
&& sessionManager != null
|
||||||
|
@ -520,10 +552,9 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initSqlSession() {
|
public void initSqlSession() {
|
||||||
if (mode == ConnectionManagementMode.EXPLICIT && connection == null) {
|
if (mode == EXPLICIT && connection == null) {
|
||||||
throw new ConnectionNotSetException();
|
throw new ConnectionNotSetException();
|
||||||
} else if (mode != ConnectionManagementMode.EXPLICIT
|
} else if (mode != EXPLICIT && !sessionManager.isManagedSessionStarted()) {
|
||||||
&& !sessionManager.isManagedSessionStarted()) {
|
|
||||||
sessionManager.startManagedSession();
|
sessionManager.startManagedSession();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package pro.taskana.common.internal.jobs;
|
package pro.taskana.common.internal.jobs;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import pro.taskana.common.api.ScheduledJob;
|
import pro.taskana.common.api.ScheduledJob;
|
||||||
import pro.taskana.common.api.TaskanaEngine;
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.api.exceptions.TaskanaException;
|
import pro.taskana.common.api.exceptions.TaskanaException;
|
||||||
|
import pro.taskana.common.internal.JobServiceImpl;
|
||||||
import pro.taskana.common.internal.TaskanaEngineImpl;
|
import pro.taskana.common.internal.TaskanaEngineImpl;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
|
|
||||||
|
@ -54,6 +57,61 @@ public abstract class AbstractTaskanaJob implements TaskanaJob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the TaskCleanupJob schedule. <br>
|
||||||
|
* All scheduled cleanup jobs are cancelled/deleted and a new one is scheduled.
|
||||||
|
*
|
||||||
|
* @param taskanaEngine the TASKANA engine.
|
||||||
|
* @param jobClass the class of the job which should be scheduled
|
||||||
|
* @throws SystemException if the jobClass could not be scheduled.
|
||||||
|
*/
|
||||||
|
public static void initializeSchedule(TaskanaEngine taskanaEngine, Class<?> jobClass) {
|
||||||
|
if (!AbstractTaskanaJob.class.isAssignableFrom(jobClass)) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format("Job '%s' is not a subclass of '%s'", jobClass, AbstractTaskanaJob.class));
|
||||||
|
}
|
||||||
|
Constructor<?> constructor;
|
||||||
|
try {
|
||||||
|
constructor =
|
||||||
|
jobClass.getConstructor(
|
||||||
|
TaskanaEngine.class, TaskanaTransactionProvider.class, ScheduledJob.class);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Job '%s' does not have a constructor matching (%s, %s, %s)",
|
||||||
|
jobClass, TaskanaEngine.class, TaskanaTransactionProvider.class, ScheduledJob.class));
|
||||||
|
}
|
||||||
|
AbstractTaskanaJob job;
|
||||||
|
try {
|
||||||
|
job = (AbstractTaskanaJob) constructor.newInstance(taskanaEngine, null, null);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Required Constructor(%s, %s, %s) of job '%s' could not be invoked",
|
||||||
|
TaskanaEngine.class, TaskanaTransactionProvider.class, ScheduledJob.class, jobClass),
|
||||||
|
e);
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Required Constructor(%s, %s, %s) of job '%s' could not be initialized",
|
||||||
|
TaskanaEngine.class, TaskanaTransactionProvider.class, ScheduledJob.class, jobClass),
|
||||||
|
e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format(
|
||||||
|
"Required Constructor(%s, %s, %s) of job '%s' is not public",
|
||||||
|
TaskanaEngine.class, TaskanaTransactionProvider.class, ScheduledJob.class, jobClass),
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
if (!job.async) {
|
||||||
|
throw new SystemException(
|
||||||
|
String.format("Job '%s' is not an async job. Please declare it as async", jobClass));
|
||||||
|
}
|
||||||
|
JobServiceImpl jobService = (JobServiceImpl) taskanaEngine.getJobService();
|
||||||
|
jobService.deleteJobs(job.getType());
|
||||||
|
job.scheduleNextJob();
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract String getType();
|
protected abstract String getType();
|
||||||
|
|
||||||
protected abstract void execute() throws TaskanaException;
|
protected abstract void execute() throws TaskanaException;
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package pro.taskana.common.internal.jobs;
|
||||||
|
|
||||||
|
public interface Clock {
|
||||||
|
void register(ClockListener listener);
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
default void stop() {}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface ClockListener {
|
||||||
|
void timeElapsed();
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import pro.taskana.common.api.ScheduledJob;
|
import pro.taskana.common.api.ScheduledJob;
|
||||||
import pro.taskana.common.api.TaskanaEngine;
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
import pro.taskana.common.internal.JobServiceImpl;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
|
|
||||||
|
@ -42,16 +41,22 @@ public class JobRunner {
|
||||||
|
|
||||||
private void runJobTransactionally(ScheduledJob scheduledJob) {
|
private void runJobTransactionally(ScheduledJob scheduledJob) {
|
||||||
TaskanaTransactionProvider.executeInTransactionIfPossible(
|
TaskanaTransactionProvider.executeInTransactionIfPossible(
|
||||||
txProvider, () -> taskanaEngine.runAsAdmin(() -> runScheduledJob(scheduledJob)));
|
txProvider,
|
||||||
|
() -> {
|
||||||
|
Boolean successful = taskanaEngine.runAsAdmin(() -> runScheduledJob(scheduledJob));
|
||||||
|
if (successful) {
|
||||||
jobService.deleteJob(scheduledJob);
|
jobService.deleteJob(scheduledJob);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void runScheduledJob(ScheduledJob scheduledJob) {
|
private boolean runScheduledJob(ScheduledJob scheduledJob) {
|
||||||
try {
|
try {
|
||||||
AbstractTaskanaJob.createFromScheduledJob(taskanaEngine, txProvider, scheduledJob).run();
|
AbstractTaskanaJob.createFromScheduledJob(taskanaEngine, txProvider, scheduledJob).run();
|
||||||
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("Error running job: {} ", scheduledJob.getType(), e);
|
LOGGER.error("Error running job: {} ", scheduledJob.getType(), e);
|
||||||
throw new SystemException(String.format("Error running job '%s'", scheduledJob.getType()), e);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package pro.taskana.common.internal.jobs;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
|
import pro.taskana.task.internal.jobs.TaskCleanupJob;
|
||||||
|
import pro.taskana.task.internal.jobs.TaskUpdatePriorityJob;
|
||||||
|
import pro.taskana.workbasket.internal.jobs.WorkbasketCleanupJob;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules the {@linkplain JobRunner} based on given {@linkplain Clock} whith given {@linkplain
|
||||||
|
* TaskanaEngine}.
|
||||||
|
*
|
||||||
|
* <p>For running the jobs the {@linkplain PlainJavaTransactionProvider} is used.
|
||||||
|
*/
|
||||||
|
public class JobScheduler {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(JobScheduler.class);
|
||||||
|
private final TaskanaEngine taskanaEngine;
|
||||||
|
|
||||||
|
private final Clock clock;
|
||||||
|
|
||||||
|
private final PlainJavaTransactionProvider plainJavaTransactionProvider;
|
||||||
|
|
||||||
|
public JobScheduler(TaskanaEngine taskanaEngine, Clock clock) {
|
||||||
|
this.taskanaEngine = taskanaEngine;
|
||||||
|
this.clock = clock;
|
||||||
|
this.plainJavaTransactionProvider =
|
||||||
|
new PlainJavaTransactionProvider(
|
||||||
|
taskanaEngine, taskanaEngine.getConfiguration().getDatasource());
|
||||||
|
plainJavaTransactionProvider.executeInTransaction(
|
||||||
|
() -> {
|
||||||
|
if (taskanaEngine.getConfiguration().isJobSchedulerEnableTaskCleanupJob()) {
|
||||||
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskCleanupJob.class);
|
||||||
|
LOGGER.info("Job '{}' enabled", TaskCleanupJob.class.getName());
|
||||||
|
}
|
||||||
|
if (taskanaEngine.getConfiguration().isJobSchedulerEnableTaskUpdatePriorityJob()) {
|
||||||
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskUpdatePriorityJob.class);
|
||||||
|
LOGGER.info("Job '{}' enabled", TaskUpdatePriorityJob.class.getName());
|
||||||
|
}
|
||||||
|
if (taskanaEngine.getConfiguration().isJobSchedulerEnableWorkbasketCleanupJob()) {
|
||||||
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, WorkbasketCleanupJob.class);
|
||||||
|
LOGGER.info("Job '{}' enabled", WorkbasketCleanupJob.class.getName());
|
||||||
|
}
|
||||||
|
if (taskanaEngine.getConfiguration().isJobSchedulerEnableUserInfoRefreshJob()) {
|
||||||
|
initJobByClassName("pro.taskana.user.jobs.UserInfoRefreshJob");
|
||||||
|
}
|
||||||
|
if (taskanaEngine.getConfiguration().isJobSchedulerEnableHistorieCleanupJob()) {
|
||||||
|
initJobByClassName("pro.taskana.simplehistory.impl.jobs.HistoryCleanupJob");
|
||||||
|
}
|
||||||
|
taskanaEngine
|
||||||
|
.getConfiguration()
|
||||||
|
.getJobSchedulerCustomJobs()
|
||||||
|
.forEach(this::initJobByClassName);
|
||||||
|
|
||||||
|
return "Initialized Jobs successfully";
|
||||||
|
});
|
||||||
|
this.clock.register(this::runAsyncJobsAsAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
clock.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
clock.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initJobByClassName(String className) throws SystemException {
|
||||||
|
try {
|
||||||
|
Class<?> jobClass = Thread.currentThread().getContextClassLoader().loadClass(className);
|
||||||
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, jobClass);
|
||||||
|
LOGGER.info("Job '{}' enabled", className);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new SystemException(String.format("Could not find class '%s'", className), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runAsyncJobsAsAdmin() {
|
||||||
|
taskanaEngine.runAsAdmin(
|
||||||
|
() -> {
|
||||||
|
JobRunner runner = new JobRunner(taskanaEngine);
|
||||||
|
runner.registerTransactionProvider(plainJavaTransactionProvider);
|
||||||
|
LOGGER.info("Running Jobs");
|
||||||
|
runner.runJobs();
|
||||||
|
return "Successful";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import javax.sql.DataSource;
|
||||||
import pro.taskana.common.api.TaskanaEngine;
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
|
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
|
import pro.taskana.common.internal.TaskanaEngineImpl;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
|
|
||||||
public class PlainJavaTransactionProvider implements TaskanaTransactionProvider {
|
public class PlainJavaTransactionProvider implements TaskanaTransactionProvider {
|
||||||
|
@ -24,15 +25,18 @@ public class PlainJavaTransactionProvider implements TaskanaTransactionProvider
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T executeInTransaction(Supplier<T> supplier) {
|
public <T> T executeInTransaction(Supplier<T> supplier) {
|
||||||
|
if (((TaskanaEngineImpl) taskanaEngine).getConnection() != null) {
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
taskanaEngine.setConnection(connection);
|
taskanaEngine.setConnection(connection);
|
||||||
final T t = supplier.get();
|
final T t = supplier.get();
|
||||||
connection.commit();
|
connection.commit();
|
||||||
|
taskanaEngine.closeConnection();
|
||||||
return t;
|
return t;
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
throw new SystemException("caught exception", ex);
|
throw new SystemException("caught exception", ex);
|
||||||
} finally {
|
} finally {
|
||||||
taskanaEngine.closeConnection();
|
|
||||||
taskanaEngine.setConnectionManagementMode(defaultConnectionManagementMode);
|
taskanaEngine.setConnectionManagementMode(defaultConnectionManagementMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package pro.taskana.common.internal.jobs;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class RealClock implements Clock {
|
||||||
|
|
||||||
|
private final long initialStartDelay;
|
||||||
|
private final long period;
|
||||||
|
private final TimeUnit periodTimeUnit;
|
||||||
|
private final List<ClockListener> listeners = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
private final ScheduledExecutorService timerService =
|
||||||
|
Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
|
public RealClock(long initialStartDelay, long period, TimeUnit periodTimeUnit) {
|
||||||
|
this.initialStartDelay = initialStartDelay;
|
||||||
|
this.period = period;
|
||||||
|
this.periodTimeUnit = periodTimeUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(ClockListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
timerService.scheduleAtFixedRate(
|
||||||
|
this::reportTimeElapse, initialStartDelay, period, periodTimeUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
timerService.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportTimeElapse() {
|
||||||
|
listeners.forEach(ClockListener::timeElapsed);
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,6 @@ import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
||||||
import pro.taskana.common.api.exceptions.MismatchedRoleException;
|
import pro.taskana.common.api.exceptions.MismatchedRoleException;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.api.exceptions.TaskanaException;
|
import pro.taskana.common.api.exceptions.TaskanaException;
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
|
||||||
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
import pro.taskana.common.internal.util.CollectionUtil;
|
import pro.taskana.common.internal.util.CollectionUtil;
|
||||||
|
@ -66,19 +65,6 @@ public class TaskCleanupJob extends AbstractTaskanaJob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the TaskCleanupJob schedule. <br>
|
|
||||||
* All scheduled cleanup jobs are cancelled/deleted and a new one is scheduled.
|
|
||||||
*
|
|
||||||
* @param taskanaEngine the TASKANA engine.
|
|
||||||
*/
|
|
||||||
public static void initializeSchedule(TaskanaEngine taskanaEngine) {
|
|
||||||
JobServiceImpl jobService = (JobServiceImpl) taskanaEngine.getJobService();
|
|
||||||
TaskCleanupJob job = new TaskCleanupJob(taskanaEngine, null, null);
|
|
||||||
jobService.deleteJobs(job.getType());
|
|
||||||
job.scheduleNextJob();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getType() {
|
protected String getType() {
|
||||||
return TaskCleanupJob.class.getName();
|
return TaskCleanupJob.class.getName();
|
||||||
|
|
|
@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory;
|
||||||
import pro.taskana.common.api.ScheduledJob;
|
import pro.taskana.common.api.ScheduledJob;
|
||||||
import pro.taskana.common.api.TaskanaEngine;
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
|
||||||
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
import pro.taskana.task.internal.jobs.helper.TaskUpdatePriorityWorker;
|
import pro.taskana.task.internal.jobs.helper.TaskUpdatePriorityWorker;
|
||||||
|
@ -61,19 +60,6 @@ public class TaskUpdatePriorityJob extends AbstractTaskanaJob {
|
||||||
return batchSize;
|
return batchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the TaskUpdatePriorityJob schedule. <br>
|
|
||||||
* All scheduled jobs are cancelled/deleted and a new one is scheduled.
|
|
||||||
*
|
|
||||||
* @param taskanaEngine the TASKANA engine.
|
|
||||||
*/
|
|
||||||
public static void initializeSchedule(TaskanaEngine taskanaEngine) {
|
|
||||||
JobServiceImpl jobService = (JobServiceImpl) taskanaEngine.getJobService();
|
|
||||||
TaskUpdatePriorityJob job = new TaskUpdatePriorityJob(taskanaEngine);
|
|
||||||
jobService.deleteJobs(job.getType());
|
|
||||||
job.scheduleNextJob();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getType() {
|
protected String getType() {
|
||||||
return TaskUpdatePriorityJob.class.getName();
|
return TaskUpdatePriorityJob.class.getName();
|
||||||
|
|
|
@ -12,7 +12,6 @@ import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
||||||
import pro.taskana.common.api.exceptions.MismatchedRoleException;
|
import pro.taskana.common.api.exceptions.MismatchedRoleException;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.api.exceptions.TaskanaException;
|
import pro.taskana.common.api.exceptions.TaskanaException;
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
|
||||||
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
import pro.taskana.common.internal.util.CollectionUtil;
|
import pro.taskana.common.internal.util.CollectionUtil;
|
||||||
|
@ -50,19 +49,6 @@ public class WorkbasketCleanupJob extends AbstractTaskanaJob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the WorkbasketCleanupJob schedule. <br>
|
|
||||||
* All scheduled cleanup jobs are cancelled/deleted and a new one is scheduled.
|
|
||||||
*
|
|
||||||
* @param taskanaEngine the taskana engine
|
|
||||||
*/
|
|
||||||
public static void initializeSchedule(TaskanaEngine taskanaEngine) {
|
|
||||||
JobServiceImpl jobService = (JobServiceImpl) taskanaEngine.getJobService();
|
|
||||||
WorkbasketCleanupJob job = new WorkbasketCleanupJob(taskanaEngine, null, null);
|
|
||||||
jobService.deleteJobs(job.getType());
|
|
||||||
job.scheduleNextJob();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getType() {
|
protected String getType() {
|
||||||
return WorkbasketCleanupJob.class.getName();
|
return WorkbasketCleanupJob.class.getName();
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -26,6 +27,7 @@ import pro.taskana.common.api.TaskanaEngine;
|
||||||
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
|
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
|
||||||
import pro.taskana.common.internal.JobMapper;
|
import pro.taskana.common.internal.JobMapper;
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
import pro.taskana.common.internal.JobServiceImpl;
|
||||||
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.internal.jobs.JobRunner;
|
import pro.taskana.common.internal.jobs.JobRunner;
|
||||||
import pro.taskana.common.test.security.JaasExtension;
|
import pro.taskana.common.test.security.JaasExtension;
|
||||||
import pro.taskana.common.test.security.WithAccessId;
|
import pro.taskana.common.test.security.WithAccessId;
|
||||||
|
@ -144,7 +146,7 @@ class TaskCleanupJobAccTest extends AbstractAccTest {
|
||||||
.filter(scheduledJob -> scheduledJob.getType().equals(TaskCleanupJob.class.getName()))
|
.filter(scheduledJob -> scheduledJob.getType().equals(TaskCleanupJob.class.getName()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
TaskCleanupJob.initializeSchedule(taskanaEngine);
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskCleanupJob.class);
|
||||||
|
|
||||||
jobsToRun = getJobMapper(taskanaEngine).findJobsToRun(Instant.now());
|
jobsToRun = getJobMapper(taskanaEngine).findJobsToRun(Instant.now());
|
||||||
|
|
||||||
|
@ -223,12 +225,16 @@ class TaskCleanupJobAccTest extends AbstractAccTest {
|
||||||
new TaskanaConfiguration.Builder(AbstractAccTest.taskanaEngineConfiguration)
|
new TaskanaConfiguration.Builder(AbstractAccTest.taskanaEngineConfiguration)
|
||||||
.cleanupJobRunEvery(runEvery)
|
.cleanupJobRunEvery(runEvery)
|
||||||
.cleanupJobFirstRun(firstRun)
|
.cleanupJobFirstRun(firstRun)
|
||||||
|
.jobSchedulerEnabled(true)
|
||||||
|
.jobSchedulerInitialStartDelay(0)
|
||||||
|
.jobSchedulerPeriod(1)
|
||||||
|
.jobSchedulerPeriodTimeUnit(TimeUnit.SECONDS)
|
||||||
|
.jobSchedulerEnableTaskCleanupJob(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
TaskanaEngine taskanaEngine =
|
TaskanaEngine taskanaEngine =
|
||||||
TaskanaEngine.buildTaskanaEngine(
|
TaskanaEngine.buildTaskanaEngine(
|
||||||
taskanaEngineConfiguration, ConnectionManagementMode.AUTOCOMMIT);
|
taskanaEngineConfiguration, ConnectionManagementMode.AUTOCOMMIT);
|
||||||
TaskCleanupJob.initializeSchedule(taskanaEngine);
|
|
||||||
|
|
||||||
List<ScheduledJob> nextJobs =
|
List<ScheduledJob> nextJobs =
|
||||||
getJobMapper(taskanaEngine).findJobsToRun(Instant.now().plus(runEvery));
|
getJobMapper(taskanaEngine).findJobsToRun(Instant.now().plus(runEvery));
|
||||||
|
@ -246,7 +252,7 @@ class TaskCleanupJobAccTest extends AbstractAccTest {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
TaskanaEngine taskanaEngine = TaskanaEngine.buildTaskanaEngine(taskanaEngineConfiguration);
|
TaskanaEngine taskanaEngine = TaskanaEngine.buildTaskanaEngine(taskanaEngineConfiguration);
|
||||||
TaskCleanupJob.initializeSchedule(taskanaEngine);
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskCleanupJob.class);
|
||||||
|
|
||||||
List<ScheduledJob> nextJobs = getJobMapper(taskanaEngine).findJobsToRun(Instant.now());
|
List<ScheduledJob> nextJobs = getJobMapper(taskanaEngine).findJobsToRun(Instant.now());
|
||||||
assertThat(nextJobs).isEmpty();
|
assertThat(nextJobs).isEmpty();
|
||||||
|
|
|
@ -19,6 +19,7 @@ import pro.taskana.common.api.ScheduledJob;
|
||||||
import pro.taskana.common.api.TaskanaEngine;
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
|
import pro.taskana.common.api.TaskanaEngine.ConnectionManagementMode;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.test.security.JaasExtension;
|
import pro.taskana.common.test.security.JaasExtension;
|
||||||
import pro.taskana.common.test.security.WithAccessId;
|
import pro.taskana.common.test.security.WithAccessId;
|
||||||
import pro.taskana.task.api.TaskQueryColumnName;
|
import pro.taskana.task.api.TaskQueryColumnName;
|
||||||
|
@ -109,11 +110,11 @@ class TaskUpdatePriorityJobAccTest extends AbstractAccTest {
|
||||||
TaskanaEngine.buildTaskanaEngine(
|
TaskanaEngine.buildTaskanaEngine(
|
||||||
taskanaEngineConfiguration, ConnectionManagementMode.AUTOCOMMIT);
|
taskanaEngineConfiguration, ConnectionManagementMode.AUTOCOMMIT);
|
||||||
// when
|
// when
|
||||||
TaskUpdatePriorityJob.initializeSchedule(taskanaEngine);
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, TaskUpdatePriorityJob.class);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(getJobMapper(taskanaEngine).findJobsToRun(someTimeInTheFuture))
|
assertThat(getJobMapper(taskanaEngine).findJobsToRun(someTimeInTheFuture))
|
||||||
.hasSizeGreaterThanOrEqualTo(1)
|
.isNotEmpty()
|
||||||
.extracting(ScheduledJob::getType)
|
.extracting(ScheduledJob::getType)
|
||||||
.contains(TaskUpdatePriorityJob.class.getName());
|
.contains(TaskUpdatePriorityJob.class.getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import pro.taskana.classification.internal.jobs.ClassificationChangedJob;
|
import pro.taskana.classification.internal.jobs.ClassificationChangedJob;
|
||||||
import pro.taskana.common.api.BaseQuery;
|
import pro.taskana.common.api.BaseQuery;
|
||||||
import pro.taskana.common.api.ScheduledJob;
|
import pro.taskana.common.api.ScheduledJob;
|
||||||
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.test.security.JaasExtension;
|
import pro.taskana.common.test.security.JaasExtension;
|
||||||
import pro.taskana.common.test.security.WithAccessId;
|
import pro.taskana.common.test.security.WithAccessId;
|
||||||
import pro.taskana.task.api.TaskState;
|
import pro.taskana.task.api.TaskState;
|
||||||
|
@ -112,7 +113,7 @@ class WorkbasketCleanupJobAccTest extends AbstractAccTest {
|
||||||
scheduledJob -> scheduledJob.getType().equals(WorkbasketCleanupJob.class.getName()))
|
scheduledJob -> scheduledJob.getType().equals(WorkbasketCleanupJob.class.getName()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
WorkbasketCleanupJob.initializeSchedule(taskanaEngine);
|
AbstractTaskanaJob.initializeSchedule(taskanaEngine, WorkbasketCleanupJob.class);
|
||||||
|
|
||||||
jobsToRun = getJobMapper(taskanaEngine).findJobsToRun(Instant.now());
|
jobsToRun = getJobMapper(taskanaEngine).findJobsToRun(Instant.now());
|
||||||
|
|
||||||
|
|
|
@ -28,12 +28,10 @@ class SqlConnectionRunnerAccTest extends AbstractAccTest {
|
||||||
// when
|
// when
|
||||||
runner.runWithConnection(
|
runner.runWithConnection(
|
||||||
connection -> {
|
connection -> {
|
||||||
ResultSet resultSet;
|
|
||||||
PreparedStatement preparedStatement =
|
PreparedStatement preparedStatement =
|
||||||
connection.prepareStatement("select * from TASK where ID = ?");
|
connection.prepareStatement("select * from TASK where ID = ?");
|
||||||
preparedStatement.setString(1, taskId);
|
preparedStatement.setString(1, taskId);
|
||||||
resultSet = preparedStatement.executeQuery();
|
ResultSet resultSet = preparedStatement.executeQuery();
|
||||||
// then
|
|
||||||
assertThat(resultSet.next()).isTrue();
|
assertThat(resultSet.next()).isTrue();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,3 +24,18 @@ taskana.workingtime.schedule.TUESDAY=00:00-00:00
|
||||||
taskana.workingtime.schedule.WEDNESDAY=00:00-00:00
|
taskana.workingtime.schedule.WEDNESDAY=00:00-00:00
|
||||||
taskana.workingtime.schedule.THURSDAY=00:00-00:00
|
taskana.workingtime.schedule.THURSDAY=00:00-00:00
|
||||||
taskana.workingtime.schedule.FRIDAY=00:00-00:00
|
taskana.workingtime.schedule.FRIDAY=00:00-00:00
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100000
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=false
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=false
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=false
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=false
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
taskana.roles.user=cn=ksc-users,cn=groups,OU=Test,O=TASKANA | teamlead-1 | teamlead-2 | user-1-1 | user-1-2 | user-2-1 | user-2-2 | user-b-1 | user-b-2
|
||||||
|
taskana.roles.admin=admin | uid=admin,cn=users,OU=Test,O=TASKANA
|
||||||
|
taskana.roles.businessadmin=businessadmin | cn=business-admins,cn=groups,OU=Test,O=TASKANA
|
||||||
|
taskana.roles.monitor=monitor | cn=monitor-users,cn=groups,OU=Test,O=TASKANA
|
||||||
|
taskana.roles.taskadmin=taskadmin
|
||||||
|
taskana.domains=DOMAIN_A , DOMAIN_B
|
||||||
|
taskana.user.minimalPermissionsToAssignDomains=READ | OPEN
|
||||||
|
taskana.classification.types=TASK , document
|
||||||
|
taskana.classification.categories.task=EXTERNAL, manual, autoMAtic, Process
|
||||||
|
taskana.classification.categories.document=EXTERNAL
|
||||||
|
taskana.jobs.maxRetries=3
|
||||||
|
taskana.jobs.batchSize=50
|
||||||
|
taskana.jobs.cleanup.runEvery=P1D
|
||||||
|
taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
|
||||||
|
taskana.jobs.cleanup.minimumAge=P0D
|
||||||
|
taskana.german.holidays.enabled=true
|
||||||
|
taskana.german.holidays.corpus-christi.enabled=false
|
||||||
|
taskana.history.deletion.on.task.deletion.enabled=true
|
||||||
|
taskana.validation.allowTimestampServiceLevelMismatch=false
|
||||||
|
taskana.query.includeLongName=false
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100000
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=false
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=false
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=false
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=false
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
|
@ -4,10 +4,12 @@ import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
|
||||||
import static pro.taskana.testapi.util.ExtensionCommunicator.getClassLevelStore;
|
import static pro.taskana.testapi.util.ExtensionCommunicator.getClassLevelStore;
|
||||||
import static pro.taskana.testapi.util.ExtensionCommunicator.isTopLevelClass;
|
import static pro.taskana.testapi.util.ExtensionCommunicator.isTopLevelClass;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import org.apache.ibatis.session.SqlSession;
|
import org.apache.ibatis.session.SqlSession;
|
||||||
|
import org.apache.ibatis.session.SqlSessionManager;
|
||||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
||||||
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
|
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
|
||||||
|
@ -27,6 +29,7 @@ import pro.taskana.common.api.security.CurrentUserContext;
|
||||||
import pro.taskana.common.internal.ConfigurationMapper;
|
import pro.taskana.common.internal.ConfigurationMapper;
|
||||||
import pro.taskana.common.internal.ConfigurationServiceImpl;
|
import pro.taskana.common.internal.ConfigurationServiceImpl;
|
||||||
import pro.taskana.common.internal.InternalTaskanaEngine;
|
import pro.taskana.common.internal.InternalTaskanaEngine;
|
||||||
|
import pro.taskana.common.internal.JobMapper;
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
import pro.taskana.common.internal.JobServiceImpl;
|
||||||
import pro.taskana.common.internal.TaskanaEngineImpl;
|
import pro.taskana.common.internal.TaskanaEngineImpl;
|
||||||
import pro.taskana.common.internal.security.CurrentUserContextImpl;
|
import pro.taskana.common.internal.security.CurrentUserContextImpl;
|
||||||
|
@ -123,6 +126,7 @@ public class TaskanaInitializationExtension implements TestInstancePostProcessor
|
||||||
UserService userService = taskanaEngine.getUserService();
|
UserService userService = taskanaEngine.getUserService();
|
||||||
SqlSession sqlSession = taskanaEngineProxy.getSqlSession();
|
SqlSession sqlSession = taskanaEngineProxy.getSqlSession();
|
||||||
WorkingTimeCalculator workingTimeCalculator = taskanaEngine.getWorkingTimeCalculator();
|
WorkingTimeCalculator workingTimeCalculator = taskanaEngine.getWorkingTimeCalculator();
|
||||||
|
JobMapper jobMapper = getJobMapper(taskanaEngine);
|
||||||
return Map.ofEntries(
|
return Map.ofEntries(
|
||||||
Map.entry(TaskanaConfiguration.class, taskanaEngine.getConfiguration()),
|
Map.entry(TaskanaConfiguration.class, taskanaEngine.getConfiguration()),
|
||||||
Map.entry(TaskanaEngineImpl.class, taskanaEngine),
|
Map.entry(TaskanaEngineImpl.class, taskanaEngine),
|
||||||
|
@ -146,6 +150,18 @@ public class TaskanaInitializationExtension implements TestInstancePostProcessor
|
||||||
Map.entry(WorkingTimeCalculatorImpl.class, workingTimeCalculator),
|
Map.entry(WorkingTimeCalculatorImpl.class, workingTimeCalculator),
|
||||||
Map.entry(ConfigurationMapper.class, sqlSession.getMapper(ConfigurationMapper.class)),
|
Map.entry(ConfigurationMapper.class, sqlSession.getMapper(ConfigurationMapper.class)),
|
||||||
Map.entry(UserService.class, userService),
|
Map.entry(UserService.class, userService),
|
||||||
Map.entry(UserServiceImpl.class, userService));
|
Map.entry(UserServiceImpl.class, userService),
|
||||||
|
Map.entry(JobMapper.class, jobMapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JobMapper getJobMapper(TaskanaEngine taskanaEngine)
|
||||||
|
throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
|
||||||
|
Field sessionManagerField = TaskanaEngineImpl.class.getDeclaredField("sessionManager");
|
||||||
|
sessionManagerField.setAccessible(true);
|
||||||
|
SqlSessionManager sqlSessionManager =
|
||||||
|
(SqlSessionManager) sessionManagerField.get(taskanaEngine);
|
||||||
|
|
||||||
|
return sqlSessionManager.getMapper(JobMapper.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,12 +89,7 @@ public class TestContainerExtension implements InvocationInterceptor {
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void copyValue(String key, Store source, Store destination) {
|
public static String determineSchemaName() {
|
||||||
Object value = source.get(key);
|
|
||||||
destination.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String determineSchemaName() {
|
|
||||||
String uniqueId = "A" + UUID.randomUUID().toString().replace("-", "_");
|
String uniqueId = "A" + UUID.randomUUID().toString().replace("-", "_");
|
||||||
if (EXECUTION_DATABASE == DB.ORACLE) {
|
if (EXECUTION_DATABASE == DB.ORACLE) {
|
||||||
uniqueId = uniqueId.substring(0, 26);
|
uniqueId = uniqueId.substring(0, 26);
|
||||||
|
@ -104,6 +99,11 @@ public class TestContainerExtension implements InvocationInterceptor {
|
||||||
return uniqueId;
|
return uniqueId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void copyValue(String key, Store source, Store destination) {
|
||||||
|
Object value = source.get(key);
|
||||||
|
destination.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
private static DB retrieveDatabaseFromEnv() {
|
private static DB retrieveDatabaseFromEnv() {
|
||||||
String property = System.getenv("DB");
|
String property = System.getenv("DB");
|
||||||
DB db;
|
DB db;
|
||||||
|
|
|
@ -18,4 +18,18 @@ taskana.german.holidays.corpus-christi.enabled=false
|
||||||
taskana.history.deletion.on.task.deletion.enabled=true
|
taskana.history.deletion.on.task.deletion.enabled=true
|
||||||
taskana.validation.allowTimestampServiceLevelMismatch=false
|
taskana.validation.allowTimestampServiceLevelMismatch=false
|
||||||
taskana.query.includeLongName=false
|
taskana.query.includeLongName=false
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100000
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=false
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=false
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=false
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=false
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
|
@ -35,8 +35,6 @@ devMode=false
|
||||||
enableCsrf=true
|
enableCsrf=true
|
||||||
####### property that control if the database is cleaned and sample data is generated
|
####### property that control if the database is cleaned and sample data is generated
|
||||||
generateSampleData=true
|
generateSampleData=true
|
||||||
####### JobScheduler cron expression that specifies when the JobSchedler runs
|
|
||||||
taskana.jobscheduler.async.cron=0 * * * * *
|
|
||||||
####### cache static resources properties
|
####### cache static resources properties
|
||||||
spring.web.resources.cache.cachecontrol.cache-private=true
|
spring.web.resources.cache.cachecontrol.cache-private=true
|
||||||
####### for upload of big workbasket- or classification-files
|
####### for upload of big workbasket- or classification-files
|
||||||
|
|
|
@ -23,3 +23,18 @@ taskana.german.holidays.enabled=true
|
||||||
taskana.german.holidays.corpus-christi.enabled=true
|
taskana.german.holidays.corpus-christi.enabled=true
|
||||||
taskana.historylogger.name=AUDIT
|
taskana.historylogger.name=AUDIT
|
||||||
taskana.routing.dmn=/dmn-table.dmn
|
taskana.routing.dmn=/dmn-table.dmn
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=true
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
package pro.taskana.example.jobs;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import pro.taskana.common.api.TaskanaEngine;
|
|
||||||
import pro.taskana.common.internal.jobs.JobRunner;
|
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
|
||||||
import pro.taskana.task.internal.jobs.TaskCleanupJob;
|
|
||||||
import pro.taskana.user.jobs.UserInfoRefreshJob;
|
|
||||||
import pro.taskana.workbasket.internal.jobs.WorkbasketCleanupJob;
|
|
||||||
|
|
||||||
/** This class invokes the JobRunner periodically to schedule long running jobs. */
|
|
||||||
@Component
|
|
||||||
public class JobScheduler {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(JobScheduler.class);
|
|
||||||
private final TaskanaTransactionProvider springTransactionProvider;
|
|
||||||
private final TaskanaEngine taskanaEngine;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public JobScheduler(
|
|
||||||
TaskanaTransactionProvider springTransactionProvider, TaskanaEngine taskanaEngine) {
|
|
||||||
this.springTransactionProvider = springTransactionProvider;
|
|
||||||
this.taskanaEngine = taskanaEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void scheduleCleanupJob()
|
|
||||||
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException,
|
|
||||||
ClassNotFoundException {
|
|
||||||
TaskCleanupJob.initializeSchedule(taskanaEngine);
|
|
||||||
WorkbasketCleanupJob.initializeSchedule(taskanaEngine);
|
|
||||||
UserInfoRefreshJob.initializeSchedule(taskanaEngine);
|
|
||||||
|
|
||||||
if (taskanaEngine.isHistoryEnabled()) {
|
|
||||||
Thread.currentThread()
|
|
||||||
.getContextClassLoader()
|
|
||||||
.loadClass("pro.taskana.simplehistory.impl.jobs.HistoryCleanupJob")
|
|
||||||
.getDeclaredMethod("initializeSchedule", TaskanaEngine.class)
|
|
||||||
.invoke(null, taskanaEngine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Scheduled(cron = "${taskana.jobscheduler.async.cron}")
|
|
||||||
public void triggerJobs() {
|
|
||||||
LOGGER.info("AsyncJobs started.");
|
|
||||||
runAsyncJobsAsAdmin();
|
|
||||||
LOGGER.info("AsyncJobs completed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runAsyncJobsAsAdmin() {
|
|
||||||
taskanaEngine.runAsAdmin(
|
|
||||||
() -> {
|
|
||||||
JobRunner runner = new JobRunner(taskanaEngine);
|
|
||||||
runner.registerTransactionProvider(springTransactionProvider);
|
|
||||||
LOGGER.info("Running Jobs");
|
|
||||||
runner.runJobs();
|
|
||||||
return "Successful";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,163 +0,0 @@
|
||||||
package pro.taskana.example.jobs;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static pro.taskana.rest.test.RestHelper.TEMPLATE;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.List;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
|
||||||
import org.springframework.hateoas.IanaLinkRelations;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
|
|
||||||
import pro.taskana.classification.api.models.Classification;
|
|
||||||
import pro.taskana.classification.rest.assembler.ClassificationRepresentationModelAssembler;
|
|
||||||
import pro.taskana.classification.rest.models.ClassificationRepresentationModel;
|
|
||||||
import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
|
||||||
import pro.taskana.common.rest.RestEndpoints;
|
|
||||||
import pro.taskana.rest.test.RestHelper;
|
|
||||||
import pro.taskana.rest.test.TaskanaSpringBootTest;
|
|
||||||
import pro.taskana.task.api.models.Task;
|
|
||||||
import pro.taskana.task.rest.assembler.TaskRepresentationModelAssembler;
|
|
||||||
import pro.taskana.task.rest.models.TaskRepresentationModel;
|
|
||||||
|
|
||||||
/** Test async updates. */
|
|
||||||
@TaskanaSpringBootTest
|
|
||||||
class AsyncUpdateJobIntTest {
|
|
||||||
|
|
||||||
private static final String CLASSIFICATION_ID = "CLI:100000000000000000000000000000000003";
|
|
||||||
|
|
||||||
private final ClassificationRepresentationModelAssembler
|
|
||||||
classificationRepresentationModelAssembler;
|
|
||||||
private final TaskRepresentationModelAssembler taskRepresentationModelAssembler;
|
|
||||||
private final JobScheduler jobScheduler;
|
|
||||||
private final RestHelper restHelper;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
AsyncUpdateJobIntTest(
|
|
||||||
ClassificationRepresentationModelAssembler classificationRepresentationModelAssembler,
|
|
||||||
TaskRepresentationModelAssembler taskRepresentationModelAssembler,
|
|
||||||
JobScheduler jobScheduler,
|
|
||||||
RestHelper restHelper) {
|
|
||||||
this.classificationRepresentationModelAssembler = classificationRepresentationModelAssembler;
|
|
||||||
this.taskRepresentationModelAssembler = taskRepresentationModelAssembler;
|
|
||||||
this.jobScheduler = jobScheduler;
|
|
||||||
this.restHelper = restHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testUpdateClassificationPrioServiceLevel() throws InvalidArgumentException {
|
|
||||||
|
|
||||||
// 1st step: get old classification :
|
|
||||||
final Instant before = Instant.now();
|
|
||||||
|
|
||||||
ResponseEntity<ClassificationRepresentationModel> response =
|
|
||||||
TEMPLATE.exchange(
|
|
||||||
restHelper.toUrl(RestEndpoints.URL_CLASSIFICATIONS_ID, CLASSIFICATION_ID),
|
|
||||||
HttpMethod.GET,
|
|
||||||
new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")),
|
|
||||||
ParameterizedTypeReference.forType(ClassificationRepresentationModel.class));
|
|
||||||
|
|
||||||
assertThat(response.getBody()).isNotNull();
|
|
||||||
ClassificationRepresentationModel classification = response.getBody();
|
|
||||||
assertThat(classification.getLink(IanaLinkRelations.SELF)).isNotNull();
|
|
||||||
|
|
||||||
// 2nd step: modify classification and trigger update
|
|
||||||
classification.removeLinks();
|
|
||||||
classification.setServiceLevel("P5D");
|
|
||||||
classification.setPriority(1000);
|
|
||||||
|
|
||||||
TEMPLATE.exchange(
|
|
||||||
restHelper.toUrl(RestEndpoints.URL_CLASSIFICATIONS_ID, CLASSIFICATION_ID),
|
|
||||||
HttpMethod.PUT,
|
|
||||||
new HttpEntity<>(classification, RestHelper.generateHeadersForUser("teamlead-1")),
|
|
||||||
ParameterizedTypeReference.forType(ClassificationRepresentationModel.class));
|
|
||||||
|
|
||||||
// trigger jobs twice to refresh all entries. first entry on the first call and follow up on the
|
|
||||||
// seconds call
|
|
||||||
jobScheduler.triggerJobs();
|
|
||||||
jobScheduler.triggerJobs();
|
|
||||||
|
|
||||||
// verify the classification modified timestamp is after 'before'
|
|
||||||
ResponseEntity<ClassificationRepresentationModel> repeatedResponse =
|
|
||||||
TEMPLATE.exchange(
|
|
||||||
restHelper.toUrl(RestEndpoints.URL_CLASSIFICATIONS_ID, CLASSIFICATION_ID),
|
|
||||||
HttpMethod.GET,
|
|
||||||
new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")),
|
|
||||||
ParameterizedTypeReference.forType(ClassificationRepresentationModel.class));
|
|
||||||
|
|
||||||
assertThat(repeatedResponse.getBody()).isNotNull();
|
|
||||||
|
|
||||||
ClassificationRepresentationModel modifiedClassificationRepresentationModel =
|
|
||||||
repeatedResponse.getBody();
|
|
||||||
Classification modifiedClassification =
|
|
||||||
classificationRepresentationModelAssembler.toEntityModel(
|
|
||||||
modifiedClassificationRepresentationModel);
|
|
||||||
|
|
||||||
assertThat(before).isBefore(modifiedClassification.getModified());
|
|
||||||
|
|
||||||
List<String> affectedTasks =
|
|
||||||
List.of(
|
|
||||||
"TKI:000000000000000000000000000000000003",
|
|
||||||
"TKI:000000000000000000000000000000000004",
|
|
||||||
"TKI:000000000000000000000000000000000005",
|
|
||||||
"TKI:000000000000000000000000000000000006",
|
|
||||||
"TKI:000000000000000000000000000000000007",
|
|
||||||
"TKI:000000000000000000000000000000000008",
|
|
||||||
"TKI:000000000000000000000000000000000009",
|
|
||||||
"TKI:000000000000000000000000000000000010",
|
|
||||||
"TKI:000000000000000000000000000000000011",
|
|
||||||
"TKI:000000000000000000000000000000000012",
|
|
||||||
"TKI:000000000000000000000000000000000013",
|
|
||||||
"TKI:000000000000000000000000000000000014",
|
|
||||||
"TKI:000000000000000000000000000000000015",
|
|
||||||
"TKI:000000000000000000000000000000000016",
|
|
||||||
"TKI:000000000000000000000000000000000017",
|
|
||||||
"TKI:000000000000000000000000000000000018",
|
|
||||||
"TKI:000000000000000000000000000000000019",
|
|
||||||
"TKI:000000000000000000000000000000000020",
|
|
||||||
"TKI:000000000000000000000000000000000021",
|
|
||||||
"TKI:000000000000000000000000000000000022",
|
|
||||||
"TKI:000000000000000000000000000000000023",
|
|
||||||
"TKI:000000000000000000000000000000000024",
|
|
||||||
"TKI:000000000000000000000000000000000025",
|
|
||||||
"TKI:000000000000000000000000000000000026",
|
|
||||||
"TKI:000000000000000000000000000000000027",
|
|
||||||
"TKI:000000000000000000000000000000000028",
|
|
||||||
"TKI:000000000000000000000000000000000029",
|
|
||||||
"TKI:000000000000000000000000000000000030",
|
|
||||||
"TKI:000000000000000000000000000000000031",
|
|
||||||
"TKI:000000000000000000000000000000000032",
|
|
||||||
"TKI:000000000000000000000000000000000033",
|
|
||||||
"TKI:000000000000000000000000000000000034",
|
|
||||||
"TKI:000000000000000000000000000000000035",
|
|
||||||
"TKI:000000000000000000000000000000000100",
|
|
||||||
"TKI:000000000000000000000000000000000101",
|
|
||||||
"TKI:000000000000000000000000000000000102",
|
|
||||||
"TKI:000000000000000000000000000000000103");
|
|
||||||
for (String taskId : affectedTasks) {
|
|
||||||
verifyTaskIsModifiedAfterOrEquals(taskId, before);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyTaskIsModifiedAfterOrEquals(String taskId, Instant before)
|
|
||||||
throws InvalidArgumentException {
|
|
||||||
|
|
||||||
ResponseEntity<TaskRepresentationModel> taskResponse =
|
|
||||||
TEMPLATE.exchange(
|
|
||||||
restHelper.toUrl(RestEndpoints.URL_TASKS_ID, taskId),
|
|
||||||
HttpMethod.GET,
|
|
||||||
new HttpEntity<>(RestHelper.generateHeadersForUser("admin")),
|
|
||||||
ParameterizedTypeReference.forType(TaskRepresentationModel.class));
|
|
||||||
|
|
||||||
TaskRepresentationModel taskRepresentationModel = taskResponse.getBody();
|
|
||||||
assertThat(taskRepresentationModel).isNotNull();
|
|
||||||
Task task = taskRepresentationModelAssembler.toEntityModel(taskRepresentationModel);
|
|
||||||
|
|
||||||
Instant modified = task.getModified();
|
|
||||||
assertThat(before).as("Task " + task.getId() + " has not been refreshed.").isBefore(modified);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,3 +14,18 @@ taskana.jobs.cleanup.runEvery=P1D
|
||||||
taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
|
taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
|
||||||
taskana.jobs.cleanup.minimumAge=P14D
|
taskana.jobs.cleanup.minimumAge=P14D
|
||||||
taskana.german.holidays.enabled=true
|
taskana.german.holidays.enabled=true
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=true
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
|
@ -19,3 +19,18 @@ taskana.jobs.history.cleanup.minimumAge=P14D
|
||||||
taskana.jobs.history.cleanup.runEvery=P1D
|
taskana.jobs.history.cleanup.runEvery=P1D
|
||||||
taskana.german.holidays.enabled=true
|
taskana.german.holidays.enabled=true
|
||||||
taskana.historylogger.name=AUDIT
|
taskana.historylogger.name=AUDIT
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=true
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=true
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=true
|
||||||
|
|
|
@ -11,7 +11,6 @@ import pro.taskana.common.api.TaskanaEngine;
|
||||||
import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
import pro.taskana.common.api.exceptions.InvalidArgumentException;
|
||||||
import pro.taskana.common.api.exceptions.MismatchedRoleException;
|
import pro.taskana.common.api.exceptions.MismatchedRoleException;
|
||||||
import pro.taskana.common.api.exceptions.SystemException;
|
import pro.taskana.common.api.exceptions.SystemException;
|
||||||
import pro.taskana.common.internal.JobServiceImpl;
|
|
||||||
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
import pro.taskana.common.internal.jobs.AbstractTaskanaJob;
|
||||||
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
import pro.taskana.common.internal.transaction.TaskanaTransactionProvider;
|
||||||
import pro.taskana.common.rest.ldap.LdapClient;
|
import pro.taskana.common.rest.ldap.LdapClient;
|
||||||
|
@ -44,19 +43,6 @@ public class UserInfoRefreshJob extends AbstractTaskanaJob {
|
||||||
refreshUserPostprocessorManager = new RefreshUserPostprocessorManager();
|
refreshUserPostprocessorManager = new RefreshUserPostprocessorManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the {@linkplain UserInfoRefreshJob} schedule. <br>
|
|
||||||
* All scheduled jobs are cancelled/deleted and a new one is scheduled.
|
|
||||||
*
|
|
||||||
* @param taskanaEngine the TASKANA engine.
|
|
||||||
*/
|
|
||||||
public static void initializeSchedule(TaskanaEngine taskanaEngine) {
|
|
||||||
JobServiceImpl jobService = (JobServiceImpl) taskanaEngine.getJobService();
|
|
||||||
UserInfoRefreshJob job = new UserInfoRefreshJob(taskanaEngine);
|
|
||||||
jobService.deleteJobs(job.getType());
|
|
||||||
job.scheduleNextJob();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getType() {
|
protected String getType() {
|
||||||
return UserInfoRefreshJob.class.getName();
|
return UserInfoRefreshJob.class.getName();
|
||||||
|
@ -74,7 +60,7 @@ public class UserInfoRefreshJob extends AbstractTaskanaJob {
|
||||||
List<User> users = ldapClient.searchUsersInUserRole();
|
List<User> users = ldapClient.searchUsersInUserRole();
|
||||||
List<User> usersAfterProcessing =
|
List<User> usersAfterProcessing =
|
||||||
users.stream()
|
users.stream()
|
||||||
.map(user -> refreshUserPostprocessorManager.processUserAfterRefresh(user))
|
.map(refreshUserPostprocessorManager::processUserAfterRefresh)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
addExistingConfigurationDataToUsers(usersAfterProcessing);
|
addExistingConfigurationDataToUsers(usersAfterProcessing);
|
||||||
clearExistingUsersAndGroups();
|
clearExistingUsersAndGroups();
|
||||||
|
|
|
@ -16,4 +16,18 @@ taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
|
||||||
taskana.jobs.cleanup.minimumAge=P14D
|
taskana.jobs.cleanup.minimumAge=P14D
|
||||||
taskana.german.holidays.enabled=true
|
taskana.german.holidays.enabled=true
|
||||||
taskana.history.deletion.on.task.deletion.enabled=true
|
taskana.history.deletion.on.task.deletion.enabled=true
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=true
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
|
@ -15,4 +15,19 @@ taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
|
||||||
taskana.jobs.cleanup.minimumAge=P14D
|
taskana.jobs.cleanup.minimumAge=P14D
|
||||||
taskana.german.holidays.enabled=true
|
taskana.german.holidays.enabled=true
|
||||||
taskana.history.deletion.on.task.deletion.enabled=true
|
taskana.history.deletion.on.task.deletion.enabled=true
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=true
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
||||||
|
|
|
@ -15,4 +15,18 @@ taskana.jobs.cleanup.firstRunAt=2018-07-25T08:00:00Z
|
||||||
taskana.jobs.cleanup.minimumAge=P14D
|
taskana.jobs.cleanup.minimumAge=P14D
|
||||||
taskana.german.holidays.enabled=true
|
taskana.german.holidays.enabled=true
|
||||||
taskana.history.deletion.on.task.deletion.enabled=true
|
taskana.history.deletion.on.task.deletion.enabled=true
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=false
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
|
@ -21,3 +21,18 @@ taskana.german.holidays.enabled=true
|
||||||
taskana.german.holidays.corpus-christi.enabled=true
|
taskana.german.holidays.corpus-christi.enabled=true
|
||||||
taskana.historylogger.name=AUDIT
|
taskana.historylogger.name=AUDIT
|
||||||
taskana.routing.dmn=/dmn-table.dmn
|
taskana.routing.dmn=/dmn-table.dmn
|
||||||
|
# enable or disable the jobscheduler at all
|
||||||
|
# set it to false and no jobs are running
|
||||||
|
taskana.jobscheduler.enabled=false
|
||||||
|
# wait time before the first job run in millis
|
||||||
|
taskana.jobscheduler.initialstartdelay=100
|
||||||
|
# sleeping time befor the next job runs
|
||||||
|
taskana.jobscheduler.period=12
|
||||||
|
# timeunit for the sleeping period
|
||||||
|
# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
|
||||||
|
taskana.jobscheduler.periodtimeunit=HOURS
|
||||||
|
taskana.jobscheduler.enableTaskCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableTaskUpdatePriorityJob=true
|
||||||
|
taskana.jobscheduler.enableWorkbasketCleanupJob=true
|
||||||
|
taskana.jobscheduler.enableUserInfoRefreshJob=false
|
||||||
|
taskana.jobscheduler.enableHistorieCleanupJob=false
|
||||||
|
|
Loading…
Reference in New Issue