TSK-1332: Reworked logic after review

This commit is contained in:
Joerg Heffner 2020-08-21 16:00:45 +02:00 committed by gitgoodjhe
parent 851b3536db
commit 32a1db98bd
10 changed files with 409 additions and 168 deletions

View File

@ -14,6 +14,10 @@ taskana.jobs.batchSize=50
taskana.jobs.cleanup.runEvery=P1D 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.jobs.history.batchSize=50
taskana.jobs.history.cleanup.firstRunAt=2018-07-25T08:00:00Z
taskana.jobs.history.cleanup.minimumAge=P14D
taskana.jobs.history.cleanup.runEvery=P1D
taskana.german.holidays.enabled=true taskana.german.holidays.enabled=true
taskana.german.holidays.corpus-christi.enabled=true taskana.german.holidays.corpus-christi.enabled=true

View File

@ -1,4 +1,8 @@
package pro.taskana.simplehistory.impl; package pro.taskana.simplehistory.impl.jobs;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -8,12 +12,10 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.HashMap; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -28,6 +30,10 @@ 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.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.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.TaskanaHistoryEngineImpl;
import pro.taskana.spi.history.api.events.task.TaskHistoryEvent;
import pro.taskana.spi.history.api.events.task.TaskHistoryEventType;
public class HistoryCleanupJob extends AbstractTaskanaJob { public class HistoryCleanupJob extends AbstractTaskanaJob {
@ -36,21 +42,25 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
private static final String TASKANA_PROPERTIES = "/taskana.properties"; private static final String TASKANA_PROPERTIES = "/taskana.properties";
private static final String TASKANA_JOB_HISTORY_BATCH_SIZE = "taskana.jobs.history.batchSize"; private static final String TASKANA_JOB_HISTORY_BATCH_SIZE = "taskana.jobs.history.batchSize";
private static final String TASKANA_JOB_HISTORY_CLEANUP_RUN_EVERY = private static final String TASKANA_JOB_HISTORY_CLEANUP_RUN_EVERY =
"taskana.jobs.history.cleanup.runEvery"; "taskana.jobs.history.cleanup.runEvery";
private static final String TASKANA_JOB_HISTORY_CLEANUP_FIRST_RUN = private static final String TASKANA_JOB_HISTORY_CLEANUP_FIRST_RUN =
"taskana.jobs.history.cleanup.firstRunAt"; "taskana.jobs.history.cleanup.firstRunAt";
private static final String TASKANA_JOB_HISTORY_CLEANUP_MINIMUM_AGE = private static final String TASKANA_JOB_HISTORY_CLEANUP_MINIMUM_AGE =
"taskana.jobs.history.cleanup.minimumAge"; "taskana.jobs.history.cleanup.minimumAge";
private final boolean allCompletedSameParentBusiness;
TaskanaHistoryEngineImpl taskanaHistoryEngine = TaskanaHistoryEngineImpl taskanaHistoryEngine =
TaskanaHistoryEngineImpl.createTaskanaEngine(taskanaEngineImpl.getConfiguration()); TaskanaHistoryEngineImpl.createTaskanaEngine(taskanaEngineImpl.getConfiguration());
private Instant firstRun; private Instant firstRun = Instant.parse("2018-01-01T00:00:00Z");
private Duration runEvery; private Duration runEvery = Duration.parse("P1D");
private Duration minimumAge; private Duration minimumAge = Duration.parse("P14D");
private int batchSize; private int batchSize = 100;
private boolean allCompletedSameParentBusiness;
public HistoryCleanupJob( public HistoryCleanupJob(
TaskanaEngine taskanaEngine, TaskanaEngine taskanaEngine,
@ -75,28 +85,52 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
SimpleHistoryServiceImpl simpleHistoryService = SimpleHistoryServiceImpl simpleHistoryService =
(SimpleHistoryServiceImpl) taskanaHistoryEngine.getTaskanaHistoryService(); (SimpleHistoryServiceImpl) taskanaHistoryEngine.getTaskanaHistoryService();
List<HistoryEventImpl> historyEventsToClean = List<TaskHistoryEvent> historyEventCandidatesToClean =
simpleHistoryService simpleHistoryService
.createHistoryQuery() .createTaskHistoryQuery()
.createdWithin(new TimeInterval(null, createdBefore)) .createdWithin(new TimeInterval(null, createdBefore))
.eventTypeIn("TASK_COMPLETED") .eventTypeIn(
TaskHistoryEventType.COMPLETED.getName(),
TaskHistoryEventType.CANCELLED.getName(),
TaskHistoryEventType.TERMINATED.getName())
.list(); .list();
List<String> taskIdsToDeleteHistoryEventsFor;
if (allCompletedSameParentBusiness) { if (allCompletedSameParentBusiness) {
historyEventsToClean =
filterSameParentBusinessHistoryEventsQualifiedToClean( String[] parentBusinessProcessIds =
simpleHistoryService, historyEventsToClean); historyEventCandidatesToClean.stream()
.map(TaskHistoryEvent::getParentBusinessProcessId)
.distinct()
.toArray(String[]::new);
historyEventCandidatesToClean.addAll(
simpleHistoryService
.createTaskHistoryQuery()
.parentBusinessProcessIdIn(parentBusinessProcessIds)
.eventTypeIn(TaskHistoryEventType.CREATED.getName())
.list());
taskIdsToDeleteHistoryEventsFor =
filterSameParentBusinessHistoryEventsQualifiedToClean(historyEventCandidatesToClean);
} else {
taskIdsToDeleteHistoryEventsFor =
historyEventCandidatesToClean.stream()
.map(TaskHistoryEvent::getTaskId)
.collect(toList());
} }
int totalNumberOfHistoryEventsDeleted = 0; int totalNumberOfHistoryEventsDeleted = 0;
while (!historyEventsToClean.isEmpty()) { while (!taskIdsToDeleteHistoryEventsFor.isEmpty()) {
int upperLimit = batchSize; int upperLimit = batchSize;
if (upperLimit > historyEventsToClean.size()) { if (upperLimit > taskIdsToDeleteHistoryEventsFor.size()) {
upperLimit = historyEventsToClean.size(); upperLimit = taskIdsToDeleteHistoryEventsFor.size();
} }
totalNumberOfHistoryEventsDeleted += totalNumberOfHistoryEventsDeleted +=
deleteHistoryEventsTransactionally(historyEventsToClean.subList(0, upperLimit)); deleteHistoryEventsTransactionally(
historyEventsToClean.subList(0, upperLimit).clear(); taskIdsToDeleteHistoryEventsFor.subList(0, upperLimit));
taskIdsToDeleteHistoryEventsFor.subList(0, upperLimit).clear();
} }
LOGGER.info( LOGGER.info(
"Job ended successfully. {} history events deleted.", totalNumberOfHistoryEventsDeleted); "Job ended successfully. {} history events deleted.", totalNumberOfHistoryEventsDeleted);
@ -118,46 +152,50 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
job.scheduleNextCleanupJob(); job.scheduleNextCleanupJob();
} }
private List<HistoryEventImpl> filterSameParentBusinessHistoryEventsQualifiedToClean( private List<String> filterSameParentBusinessHistoryEventsQualifiedToClean(
SimpleHistoryServiceImpl simpleHistoryService, List<HistoryEventImpl> historyEventsToClean) { List<TaskHistoryEvent> historyEventCandidatesToClean) {
Map<String, Long> eventsToCleanForParentBusinessCount = new HashMap<>(); Map<String, Map<String, List<String>>> historyEventsGroupedByParentBusinessProcessIdAndType =
historyEventCandidatesToClean.stream()
.collect(
groupingBy(
TaskHistoryEvent::getParentBusinessProcessId,
groupingBy(
TaskHistoryEvent::getEventType,
mapping(TaskHistoryEvent::getTaskId, toList()))));
historyEventsToClean.forEach( List<String> taskIdsToDeleteHistoryEventsFor = new ArrayList<>();
event ->
eventsToCleanForParentBusinessCount.merge(
event.getParentBusinessProcessId(), 1L, Long::sum));
Predicate<HistoryEventImpl> noCompletedEventsUnderMinimumAgeExistInSameParentBusiness = historyEventsGroupedByParentBusinessProcessIdAndType
event -> .entrySet()
simpleHistoryService .forEach(
.createHistoryQuery() idsOfTasksInSameParentBusinessProcessGroupedByType -> {
.parentBusinessProcessIdIn(event.getParentBusinessProcessId()) if (idsOfTasksInSameParentBusinessProcessGroupedByType
.eventTypeIn("TASK_COMPLETED") .getValue()
.count() .get(TaskHistoryEventType.CREATED.getName())
== eventsToCleanForParentBusinessCount.get(event.getParentBusinessProcessId()); .size()
== idsOfTasksInSameParentBusinessProcessGroupedByType.getValue().entrySet()
.stream()
.filter(
entry -> !entry.getKey().equals(TaskHistoryEventType.CREATED.getName()))
.mapToInt(stringListEntry -> stringListEntry.getValue().size())
.sum()) {
Predicate<HistoryEventImpl> allTasksCleanedSameParentBusiness = taskIdsToDeleteHistoryEventsFor.addAll(
e -> idsOfTasksInSameParentBusinessProcessGroupedByType
taskanaEngineImpl .getValue()
.getTaskService() .get(TaskHistoryEventType.CREATED.getName()));
.createTaskQuery() }
.parentBusinessProcessIdIn(e.getParentBusinessProcessId()) });
.count()
== 0;
return historyEventsToClean.stream() return taskIdsToDeleteHistoryEventsFor;
.filter(
noCompletedEventsUnderMinimumAgeExistInSameParentBusiness.and(
allTasksCleanedSameParentBusiness))
.collect(Collectors.toList());
} }
private int deleteHistoryEventsTransactionally(List<HistoryEventImpl> historyEventsToBeDeleted) { private int deleteHistoryEventsTransactionally(List<String> taskIdsToDeleteHistoryEventsFor) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug( LOGGER.debug(
"entry to deleteHistoryEventsTransactionally(historyEventsToBeDeleted = {})", "entry to deleteHistoryEventsTransactionally(taskIdsToDeleteHistoryEventsFor = {})",
historyEventsToBeDeleted); taskIdsToDeleteHistoryEventsFor);
} }
int deletedEventsCount = 0; int deletedEventsCount = 0;
@ -167,7 +205,7 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
txProvider.executeInTransaction( txProvider.executeInTransaction(
() -> { () -> {
try { try {
return deleteEvents(historyEventsToBeDeleted); return deleteEvents(taskIdsToDeleteHistoryEventsFor);
} catch (Exception e) { } catch (Exception e) {
LOGGER.warn("Could not delete history events.", e); LOGGER.warn("Could not delete history events.", e);
return 0; return 0;
@ -177,7 +215,7 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
return count; return count;
} else { } else {
try { try {
deletedEventsCount = deleteEvents(historyEventsToBeDeleted); deletedEventsCount = deleteEvents(taskIdsToDeleteHistoryEventsFor);
} catch (Exception e) { } catch (Exception e) {
LOGGER.warn("Could not delete history events.", e); LOGGER.warn("Could not delete history events.", e);
} }
@ -187,34 +225,30 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
return deletedEventsCount; return deletedEventsCount;
} }
private int deleteEvents(List<HistoryEventImpl> historyEventsToBeDeleted) private int deleteEvents(List<String> taskIdsToDeleteHistoryEventsFor)
throws InvalidArgumentException, NotAuthorizedException { throws InvalidArgumentException, NotAuthorizedException {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug( LOGGER.debug(
"entry to deleteEvents(historyEventsToBeDeleted = {})", historyEventsToBeDeleted); "entry to deleteEvents(taskIdsToDeleteHistoryEventsFor = {})",
taskIdsToDeleteHistoryEventsFor);
} }
List<String> taskIdsOfEventsToBeDeleted =
historyEventsToBeDeleted.stream()
.map(HistoryEventImpl::getTaskId)
.collect(Collectors.toList());
SimpleHistoryServiceImpl simpleHistoryService = SimpleHistoryServiceImpl simpleHistoryService =
(SimpleHistoryServiceImpl) taskanaHistoryEngine.getTaskanaHistoryService(); (SimpleHistoryServiceImpl) taskanaHistoryEngine.getTaskanaHistoryService();
String[] taskIdsArray = new String[taskIdsOfEventsToBeDeleted.size()]; String[] taskIdsArray = new String[taskIdsToDeleteHistoryEventsFor.size()];
int deletedTasksCount = int deletedTasksCount =
(int) (int)
simpleHistoryService simpleHistoryService
.createHistoryQuery() .createTaskHistoryQuery()
.taskIdIn(taskIdsOfEventsToBeDeleted.toArray(taskIdsArray)) .taskIdIn(taskIdsToDeleteHistoryEventsFor.toArray(taskIdsArray))
.count(); .count();
simpleHistoryService.deleteHistoryEventsByTaskIds(taskIdsOfEventsToBeDeleted); simpleHistoryService.deleteHistoryEventsByTaskIds(taskIdsToDeleteHistoryEventsFor);
LOGGER.debug("{} events deleted.", deletedTasksCount); LOGGER.debug("{} events deleted.", deletedTasksCount);
LOGGER.debug("exit from deleteEvents(), returning {}", taskIdsOfEventsToBeDeleted.size()); LOGGER.debug("exit from deleteEvents(), returning {}", taskIdsToDeleteHistoryEventsFor.size());
return deletedTasksCount; return deletedTasksCount;
} }
@ -315,8 +349,10 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
"taskana properties were loaded from file {} from classpath.", propertiesFile); "taskana properties were loaded from file {} from classpath.", propertiesFile);
} }
} else { } else {
props.load(new FileInputStream(propertiesFile)); try (FileInputStream fileInputStream = new FileInputStream(propertiesFile)) {
LOGGER.debug("taskana properties were loaded from file {}.", propertiesFile); props.load(fileInputStream);
LOGGER.debug("taskana properties were loaded from file {}.", propertiesFile);
}
} }
} catch (IOException e) { } catch (IOException e) {
LOGGER.error("caught IOException when processing properties file {}.", propertiesFile); LOGGER.error("caught IOException when processing properties file {}.", propertiesFile);

View File

@ -11,8 +11,9 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.simplehistory.impl.HistoryCleanupJob; import pro.taskana.simplehistory.impl.jobs.HistoryCleanupJob;
import pro.taskana.simplehistory.impl.HistoryEventImpl; import pro.taskana.spi.history.api.events.task.TaskHistoryEvent;
import pro.taskana.spi.history.api.events.task.TaskHistoryEventType;
@ExtendWith(JaasExtension.class) @ExtendWith(JaasExtension.class)
class HistoryCleanupJobAccTest extends AbstractAccTest { class HistoryCleanupJobAccTest extends AbstractAccTest {
@ -27,128 +28,336 @@ class HistoryCleanupJobAccTest extends AbstractAccTest {
void should_CleanHistoryEventsUntilDate_When_SameParentBusinessTrueAndEventsQualified() void should_CleanHistoryEventsUntilDate_When_SameParentBusinessTrueAndEventsQualified()
throws Exception { throws Exception {
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(13); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(13);
HistoryEventImpl eventToBeCleaned = TaskHistoryEvent eventToBeCleaned =
createHistoryEvent( createTaskHistoryEvent(
"wbKey1", "taskId1", "TASK_COMPLETED", "wbKey2", "someUserId", "someDetails"); "wbKey1",
"taskId1",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned.setCreated(Instant.now().minus(20, ChronoUnit.DAYS)); eventToBeCleaned.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned.setParentBusinessProcessId("sameParentId"); eventToBeCleaned.setParentBusinessProcessId("sameParentId");
HistoryEventImpl eventToBeCleaned2 = TaskHistoryEvent eventToBeCleaned2 =
createHistoryEvent( createTaskHistoryEvent(
"wbKey1", "taskId2", "TASK_COMPLETED", "wbKey2", "someUserId", "someDetails"); "wbKey1",
"taskId1",
TaskHistoryEventType.COMPLETED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned2.setCreated(Instant.now().minus(20, ChronoUnit.DAYS)); eventToBeCleaned2.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned2.setParentBusinessProcessId("sameParentId"); eventToBeCleaned2.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned3 =
createTaskHistoryEvent(
"wbKey1",
"taskId2",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned3.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned3.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned4 =
createTaskHistoryEvent(
"wbKey1",
"taskId2",
TaskHistoryEventType.CANCELLED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned4.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned4.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned5 =
createTaskHistoryEvent(
"wbKey1",
"taskId3",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned5.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned5.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned6 =
createTaskHistoryEvent(
"wbKey1",
"taskId3",
TaskHistoryEventType.TERMINATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned6.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned6.setParentBusinessProcessId("sameParentId");
getHistoryService().create(eventToBeCleaned); getHistoryService().create(eventToBeCleaned);
getHistoryService().create(eventToBeCleaned2); getHistoryService().create(eventToBeCleaned2);
getHistoryService().create(eventToBeCleaned3);
getHistoryService().create(eventToBeCleaned4);
getHistoryService().create(eventToBeCleaned5);
getHistoryService().create(eventToBeCleaned6);
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(15); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(19);
taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(true); taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(true);
HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null); HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null);
job.run(); job.run();
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(13); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(13);
} }
@Test @Test
@WithAccessId(user = "admin") @WithAccessId(user = "admin")
void should_NotCleanHistoryEventsUntilDate_When_SameParentBusinessTrueAndEventsNotQualified() void should_NotCleanHistoryEventsUntilDate_When_MinimumAgeNotReached() throws Exception {
throws Exception {
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(13); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(13);
HistoryEventImpl eventToBeCleaned = TaskHistoryEvent eventToBeCleaned =
createHistoryEvent( createTaskHistoryEvent(
"wbKey1", "taskId1", "TASK_COMPLETED", "wbKey2", "someUserId", "someDetails");
eventToBeCleaned.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned.setParentBusinessProcessId("sameParentId");
HistoryEventImpl eventToBeCleaned2 =
createHistoryEvent(
"wbKey1", "taskId2", "TASK_COMPLETED", "wbKey2", "someUserId", "someDetails");
eventToBeCleaned2.setCreated(Instant.now().minus(1, ChronoUnit.DAYS));
eventToBeCleaned2.setParentBusinessProcessId("sameParentId");
HistoryEventImpl eventToBeCleaned3 =
createHistoryEvent(
"wbKey1", "wbKey1",
"TKI:000000000000000000000000000000000001", "taskId1",
"TASK_COMPLETED", TaskHistoryEventType.CREATED.getName(),
"wbKey2", "wbKey2",
"someUserId", "someUserId",
"someDetails"); "someDetails");
eventToBeCleaned3.setCreated(Instant.now().minus(20, ChronoUnit.DAYS)); eventToBeCleaned.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned3.setParentBusinessProcessId("PBPI21"); eventToBeCleaned.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned2 =
createTaskHistoryEvent(
"wbKey1",
"taskId1",
TaskHistoryEventType.COMPLETED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned2.setCreated(Instant.now().minus(5, ChronoUnit.DAYS));
eventToBeCleaned2.setParentBusinessProcessId("sameParentId");
getHistoryService().create(eventToBeCleaned);
getHistoryService().create(eventToBeCleaned2);
assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(15);
HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null);
job.run();
assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(15);
}
@Test
@WithAccessId(user = "admin")
void should_NotCleanHistoryEvents_When_SameParentBusinessTrueAndActiveTaskInParentBusiness()
throws Exception {
assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(13);
TaskHistoryEvent eventToBeCleaned =
createTaskHistoryEvent(
"wbKey1",
"taskId1",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned2 =
createTaskHistoryEvent(
"wbKey1",
"taskId1",
TaskHistoryEventType.COMPLETED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned2.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned2.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned3 =
createTaskHistoryEvent(
"wbKey1",
"taskId2",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned3.setCreated(Instant.now().minus(1, ChronoUnit.DAYS));
eventToBeCleaned3.setParentBusinessProcessId("sameParentId");
getHistoryService().create(eventToBeCleaned); getHistoryService().create(eventToBeCleaned);
getHistoryService().create(eventToBeCleaned2); getHistoryService().create(eventToBeCleaned2);
getHistoryService().create(eventToBeCleaned3); getHistoryService().create(eventToBeCleaned3);
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(16); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(16);
taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(true); taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(true);
HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null); HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null);
job.run(); job.run();
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(16); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(16);
}
@Test
@WithAccessId(user = "admin")
void should_NotCleanHistoryEvents_When_MinimumAgeOfOtherEndtstateEventInParentBusinessNotReached()
throws Exception {
assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(13);
TaskHistoryEvent eventToBeCleaned =
createTaskHistoryEvent(
"wbKey1",
"taskId1",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned2 =
createTaskHistoryEvent(
"wbKey1",
"taskId1",
TaskHistoryEventType.COMPLETED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned2.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned2.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned3 =
createTaskHistoryEvent(
"wbKey1",
"taskId2",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned3.setCreated(Instant.now().minus(3, ChronoUnit.DAYS));
eventToBeCleaned3.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned4 =
createTaskHistoryEvent(
"wbKey1",
"taskId2",
TaskHistoryEventType.CANCELLED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned4.setCreated(Instant.now().minus(5, ChronoUnit.DAYS));
eventToBeCleaned4.setParentBusinessProcessId("sameParentId");
getHistoryService().create(eventToBeCleaned);
getHistoryService().create(eventToBeCleaned2);
getHistoryService().create(eventToBeCleaned3);
getHistoryService().create(eventToBeCleaned4);
assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(17);
taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(true);
HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null);
job.run();
assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(17);
} }
@Test @Test
@WithAccessId(user = "admin") @WithAccessId(user = "admin")
void should_CleanHistoryEventsUntilDate_When_SameParentBusinessFalse() throws Exception { void should_CleanHistoryEventsUntilDate_When_SameParentBusinessFalse() throws Exception {
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(13); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(13);
HistoryEventImpl eventToBeCleaned = TaskHistoryEvent eventToBeCleaned =
createHistoryEvent( createTaskHistoryEvent(
"wbKey1", "taskId1", "TASK_COMPLETED", "wbKey2", "someUserId", "someDetails"); "wbKey1",
"taskId1",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned.setCreated(Instant.now().minus(20, ChronoUnit.DAYS)); eventToBeCleaned.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned.setParentBusinessProcessId("sameParentId"); eventToBeCleaned.setParentBusinessProcessId("sameParentId");
HistoryEventImpl eventToBeCleaned2 = TaskHistoryEvent eventToBeCleaned2 =
createHistoryEvent( createTaskHistoryEvent(
"wbKey1", "taskId2", "TASK_COMPLETED", "wbKey2", "someUserId", "someDetails"); "wbKey1",
eventToBeCleaned2.setCreated(Instant.now().minus(1, ChronoUnit.DAYS)); "taskId1",
TaskHistoryEventType.COMPLETED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned2.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned2.setParentBusinessProcessId("sameParentId"); eventToBeCleaned2.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned3 =
createTaskHistoryEvent(
"wbKey1",
"taskId2",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned3.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned3.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned4 =
createTaskHistoryEvent(
"wbKey1",
"taskId2",
TaskHistoryEventType.CANCELLED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned4.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned4.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned5 =
createTaskHistoryEvent(
"wbKey1",
"taskId3",
TaskHistoryEventType.CREATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned5.setCreated(Instant.now().minus(20, ChronoUnit.DAYS));
eventToBeCleaned5.setParentBusinessProcessId("sameParentId");
TaskHistoryEvent eventToBeCleaned6 =
createTaskHistoryEvent(
"wbKey1",
"taskId3",
TaskHistoryEventType.TERMINATED.getName(),
"wbKey2",
"someUserId",
"someDetails");
eventToBeCleaned6.setCreated(Instant.now().minus(5, ChronoUnit.DAYS));
eventToBeCleaned6.setParentBusinessProcessId("sameParentId");
getHistoryService().create(eventToBeCleaned); getHistoryService().create(eventToBeCleaned);
getHistoryService().create(eventToBeCleaned2); getHistoryService().create(eventToBeCleaned2);
getHistoryService().create(eventToBeCleaned3);
getHistoryService().create(eventToBeCleaned4);
getHistoryService().create(eventToBeCleaned5);
getHistoryService().create(eventToBeCleaned6);
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(15); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(19);
taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(false); taskanaEngine.getConfiguration().setTaskCleanupJobAllCompletedSameParentBusiness(false);
HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null); HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null);
job.run(); job.run();
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(14); assertThat(getHistoryService().createTaskHistoryQuery().count()).isEqualTo(15);
assertThat(getHistoryService().getHistoryEvent(eventToBeCleaned2.getId())).isNotNull();
}
@Test
@WithAccessId(user = "admin")
void should_NotCleanHistoryEvents_When_MinimumAgeNotReached() throws Exception {
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(13);
HistoryEventImpl eventToBeCleaned =
createHistoryEvent(
"wbKey1", "taskId1", "TASK_COMPLETED", "wbKey2", "someUserId", "someDetails");
eventToBeCleaned.setCreated(Instant.now().minus(1, ChronoUnit.DAYS));
eventToBeCleaned.setParentBusinessProcessId("sameParentId");
getHistoryService().create(eventToBeCleaned);
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(14);
HistoryCleanupJob job = new HistoryCleanupJob(taskanaEngine, null, null);
job.run();
assertThat(getHistoryService().createHistoryQuery().count()).isEqualTo(14);
} }
} }

View File

@ -181,7 +181,7 @@ public class ScheduledJob {
UPDATETASKSJOB(TaskRefreshJob.class.getName()), UPDATETASKSJOB(TaskRefreshJob.class.getName()),
TASKCLEANUPJOB(TaskCleanupJob.class.getName()), TASKCLEANUPJOB(TaskCleanupJob.class.getName()),
WORKBASKETCLEANUPJOB(WorkbasketCleanupJob.class.getName()), WORKBASKETCLEANUPJOB(WorkbasketCleanupJob.class.getName()),
HISTORYCLEANUPJOB("pro.taskana.simplehistory.impl.HistoryCleanupJob"); HISTORYCLEANUPJOB("pro.taskana.simplehistory.impl.jobs.HistoryCleanupJob");
private String clazz; private String clazz;

View File

@ -5,15 +5,10 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import pro.taskana.classification.internal.jobs.ClassificationChangedJob;
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.TaskanaException;
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;
import pro.taskana.task.internal.jobs.TaskCleanupJob;
import pro.taskana.task.internal.jobs.TaskRefreshJob;
import pro.taskana.workbasket.internal.jobs.WorkbasketCleanupJob;
/** Abstract base for all background jobs of TASKANA. */ /** Abstract base for all background jobs of TASKANA. */
public abstract class AbstractTaskanaJob implements TaskanaJob { public abstract class AbstractTaskanaJob implements TaskanaJob {
@ -33,34 +28,15 @@ public abstract class AbstractTaskanaJob implements TaskanaJob {
public static TaskanaJob createFromScheduledJob( public static TaskanaJob createFromScheduledJob(
TaskanaEngine engine, TaskanaTransactionProvider<Object> txProvider, ScheduledJob job) TaskanaEngine engine, TaskanaTransactionProvider<Object> txProvider, ScheduledJob job)
throws TaskanaException, ClassNotFoundException, IllegalAccessException, throws ClassNotFoundException, IllegalAccessException, InstantiationException,
InstantiationException, InvocationTargetException { InvocationTargetException {
switch (job.getType()) { return (TaskanaJob)
case CLASSIFICATIONCHANGEDJOB: Thread.currentThread()
return new ClassificationChangedJob(engine, txProvider, job); .getContextClassLoader()
case UPDATETASKSJOB: .loadClass(job.getType().getClazz())
return new TaskRefreshJob(engine, txProvider, job); .getConstructors()[0]
case TASKCLEANUPJOB: .newInstance(engine, txProvider, job);
return new TaskCleanupJob(engine, txProvider, job);
case WORKBASKETCLEANUPJOB:
return new WorkbasketCleanupJob(engine, txProvider, job);
case HISTORYCLEANUPJOB:
return (TaskanaJob)
Thread.currentThread()
.getContextClassLoader()
.loadClass(job.getType().getClazz())
.getConstructors()[0]
.newInstance(engine, txProvider, job);
default:
throw new TaskanaException(
"No matching job found for "
+ job.getType()
+ " of ScheduledJob "
+ job.getJobId()
+ ".");
}
} }
protected <T> List<List<T>> partition(Collection<T> members, int maxSize) { protected <T> List<List<T>> partition(Collection<T> members, int maxSize) {

View File

@ -13,3 +13,7 @@ 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=PT0S taskana.jobs.cleanup.minimumAge=PT0S
taskana.jobs.cleanup.allCompletedSameParentBusiness=false taskana.jobs.cleanup.allCompletedSameParentBusiness=false
taskana.jobs.history.batchSize=50
taskana.jobs.history.cleanup.firstRunAt=2018-07-25T08:00:00Z
taskana.jobs.history.cleanup.minimumAge=P14D
taskana.jobs.history.cleanup.runEvery=P1D

View File

@ -14,6 +14,10 @@ taskana.jobs.batchSize=50
taskana.jobs.cleanup.runEvery=P1D 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.jobs.history.batchSize=50
taskana.jobs.history.cleanup.firstRunAt=2018-07-25T08:00:00Z
taskana.jobs.history.cleanup.minimumAge=P14D
taskana.jobs.history.cleanup.runEvery=P1D
taskana.german.holidays.enabled=true 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

View File

@ -14,4 +14,8 @@ taskana.jobs.batchSize=50
taskana.jobs.cleanup.runEvery=P1D 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.jobs.history.batchSize=50
taskana.jobs.history.cleanup.firstRunAt=2018-07-25T08:00:00Z
taskana.jobs.history.cleanup.minimumAge=P14D
taskana.jobs.history.cleanup.runEvery=P1D
taskana.german.holidays.enabled=true taskana.german.holidays.enabled=true

View File

@ -28,7 +28,7 @@ import pro.taskana.workbasket.rest.models.WorkbasketSummaryRepresentationModel;
public class AbstractAccTest { public class AbstractAccTest {
protected static final String DEPENDENCY_VERSION = "4.0.1-SNAPSHOT"; protected static final String DEPENDENCY_VERSION = "4.0.2-SNAPSHOT";
private static final String AUTHORIZATION_TEAMLEAD_1 = "Basic dGVhbWxlYWQtMTp0ZWFtbGVhZC0x"; private static final String AUTHORIZATION_TEAMLEAD_1 = "Basic dGVhbWxlYWQtMTp0ZWFtbGVhZC0x";
/** /**

View File

@ -14,5 +14,9 @@ taskana.jobs.batchSize=50
taskana.jobs.cleanup.runEvery=P1D 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.jobs.history.batchSize=50
taskana.jobs.history.cleanup.firstRunAt=2018-07-25T08:00:00Z
taskana.jobs.history.cleanup.minimumAge=P14D
taskana.jobs.history.cleanup.runEvery=P1D
taskana.german.holidays.enabled=true taskana.german.holidays.enabled=true
taskana.historylogger.name=AUDIT taskana.historylogger.name=AUDIT