Skip to content

Commit d768632

Browse files
authored
feat: Old messages are deleted after a configurable time (default is after 180 days) with all associated data.
- Integrates scheduled jobs which deletes the old messages. - Sets the default property values in application.properties. - Extends the repositories for the necessary methods. PR #773
1 parent eadb139 commit d768632

5 files changed

Lines changed: 147 additions & 1 deletion

File tree

iris-client-bff/src/main/java/iris/client_bff/iris_messages/IrisMessage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public class IrisMessage extends Aggregate<IrisMessage, IrisMessage.IrisMessageI
6969

7070
private boolean isRead;
7171

72-
@OneToMany(mappedBy = "message", cascade = CascadeType.ALL, orphanRemoval = true)
72+
@OneToMany(mappedBy = "message", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
7373
private List<IrisMessageData> dataAttachments = new ArrayList<>();
7474

7575
@EqualsAndHashCode(callSuper = false)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package iris.client_bff.iris_messages;
2+
3+
import iris.client_bff.iris_messages.IrisMessage.IrisMessageIdentifier;
4+
import lombok.Getter;
5+
import lombok.NonNull;
6+
import lombok.RequiredArgsConstructor;
7+
import lombok.extern.slf4j.Slf4j;
8+
9+
import java.time.Duration;
10+
import java.time.Instant;
11+
import java.util.stream.Collectors;
12+
13+
import javax.transaction.Transactional;
14+
15+
import org.springframework.boot.context.properties.ConfigurationProperties;
16+
import org.springframework.boot.context.properties.ConstructorBinding;
17+
import org.springframework.scheduling.annotation.Scheduled;
18+
import org.springframework.stereotype.Component;
19+
20+
/**
21+
* This class collects all old events and deletes this.
22+
*
23+
* @author Jens Kutzsche
24+
*/
25+
@Component
26+
@Slf4j
27+
@RequiredArgsConstructor
28+
class IrisMessageDeleteJob {
29+
30+
private final @NonNull IrisMessageRepository messageRepo;
31+
private final @NonNull Properties properties;
32+
33+
@Transactional
34+
@Scheduled(cron = "${iris.client.message.delete-cron:-}")
35+
void deleteMessages() {
36+
37+
var refDate = Instant.now().minus(properties.getDeleteAfter());
38+
39+
var oldMessages = messageRepo.findByMetadataCreatedIsBefore(refDate).toList();
40+
41+
if (oldMessages.isEmpty()) {
42+
return;
43+
}
44+
45+
log.debug("{} IRIS message(s) are deleted with period {} after their creation!",
46+
oldMessages.size(),
47+
properties.getDeleteAfter(),
48+
oldMessages.get(0).getCreatedAt());
49+
50+
messageRepo.deleteAll(oldMessages);
51+
52+
log.info("{} IRIS message(s) (IDs: {}) were deleted with period {} after their creation at {}!",
53+
oldMessages.size(),
54+
oldMessages.stream()
55+
.map(IrisMessage::getId)
56+
.map(IrisMessageIdentifier::toString)
57+
.collect(Collectors.joining(", ")),
58+
properties.getDeleteAfter(),
59+
oldMessages.get(0).getCreatedAt());
60+
}
61+
62+
@ConstructorBinding
63+
@RequiredArgsConstructor
64+
@ConfigurationProperties("iris.client.message")
65+
@Getter
66+
public static class Properties {
67+
68+
/**
69+
* Defines the {@link Duration} after that a IRIS message will be deleted starting from the creation date.
70+
*/
71+
private final Duration deleteAfter;
72+
}
73+
}

iris-client-bff/src/main/java/iris/client_bff/iris_messages/IrisMessageRepository.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package iris.client_bff.iris_messages;
22

3+
import java.time.Instant;
4+
35
import org.springframework.data.domain.Page;
46
import org.springframework.data.domain.Pageable;
57
import org.springframework.data.jpa.repository.JpaRepository;
68
import org.springframework.data.jpa.repository.Query;
9+
import org.springframework.data.util.Streamable;
710

811
public interface IrisMessageRepository extends JpaRepository<IrisMessage, IrisMessage.IrisMessageIdentifier> {
912

@@ -15,4 +18,11 @@ public interface IrisMessageRepository extends JpaRepository<IrisMessage, IrisMe
1518
Page<IrisMessage> findAllByFolderIdOrderByIsReadAsc(IrisMessageFolder.IrisMessageFolderIdentifier folder,
1619
Pageable pageable);
1720

21+
/**
22+
* Returns the {@link IrisMessage}s created before the given {@link Instant}.
23+
*
24+
* @param refDate must not be {@literal null}.
25+
* @return
26+
*/
27+
Streamable<IrisMessage> findByMetadataCreatedIsBefore(Instant refDate);
1828
}

iris-client-bff/src/main/resources/application.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ iris.client.vaccinfo.delete-after=6m
1818
iris.client.vaccinfo.delete-cron=0 32 1 * * *
1919
iris.client.vaccinfo.announcement.delete-after=2h
2020
iris.client.vaccinfo.announcement.delete-cron=0 10 * * * *
21+
iris.client.message.delete-after=180d
22+
iris.client.message.delete-cron=0 33 1 * * *
2123
iris.client.message.build-recipient-list.delay=900000
2224

2325
iris.client.vaccinfo.expiration-duration=2h
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package iris.client_bff.iris_messages;
2+
3+
import static java.time.Duration.*;
4+
import static org.assertj.core.api.Assertions.*;
5+
6+
import iris.client_bff.IrisWebIntegrationTest;
7+
import iris.client_bff.core.IrisDateTimeProvider;
8+
import lombok.RequiredArgsConstructor;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
/**
13+
* @author Jens Kutzsche
14+
*/
15+
@IrisWebIntegrationTest
16+
@RequiredArgsConstructor
17+
class IrisMessageDeleteJobIntegrationTests {
18+
19+
private final IrisMessageRepository messageRepo;
20+
private final IrisMessageDataRepository dataRepo;
21+
private final IrisMessageFolderRepository folderRepo;
22+
private final IrisDateTimeProvider dateTimeProvider;
23+
private final IrisMessageDeleteJob deleteJob;
24+
25+
@Test
26+
void testDeleteMessages() {
27+
28+
var messagesSize = messageRepo.findAll().size();
29+
var dataSize = dataRepo.findAll().size();
30+
31+
// in time
32+
dateTimeProvider.setDelta(ofDays(-179));
33+
34+
createMessage();
35+
36+
// to old
37+
dateTimeProvider.setDelta(ofDays(-181));
38+
39+
createMessage();
40+
41+
dateTimeProvider.reset();
42+
43+
// extra element from data initialization
44+
assertThat(messageRepo.findAll()).hasSize(messagesSize + 2);
45+
assertThat(dataRepo.findAll()).hasSize(dataSize + 2);
46+
47+
deleteJob.deleteMessages();
48+
49+
assertThat(messageRepo.findAll()).hasSize(messagesSize + 1);
50+
assertThat(dataRepo.findAll()).hasSize(dataSize + 1);
51+
}
52+
53+
private void createMessage() {
54+
55+
var testData = new IrisMessageTestData();
56+
57+
var folder = this.folderRepo.findFirstByContextAndParentFolderIsNull(IrisMessageContext.INBOX).get();
58+
59+
messageRepo.save(testData.getTestInboxMessage(folder));
60+
}
61+
}

0 commit comments

Comments
 (0)