Skip to content

Commit 4223464

Browse files
authored
Merge pull request #348 from mp-access/hotfix/cleanup-in-memory-repo
Hotfix/cleanup in memory repo
2 parents 8588930 + 640ebdb commit 4223464

5 files changed

Lines changed: 138 additions & 0 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ch.uzh.ifi.access.student.config;
2+
3+
import ch.uzh.ifi.access.student.evaluation.process.EvalMachineRepoService;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.scheduling.annotation.EnableScheduling;
8+
import org.springframework.scheduling.annotation.Scheduled;
9+
10+
import java.time.Instant;
11+
import java.time.temporal.ChronoUnit;
12+
13+
@Configuration
14+
@EnableScheduling
15+
public class SchedulingConfig {
16+
17+
private static Logger logger = LoggerFactory.getLogger(SchedulingConfig.class);
18+
19+
private static final long FIXED_DELAY_IN_MINUTES = 5;
20+
21+
private EvalMachineRepoService machineRepository;
22+
23+
public SchedulingConfig(EvalMachineRepoService machineRepository) {
24+
this.machineRepository = machineRepository;
25+
}
26+
27+
@Scheduled(fixedDelay = FIXED_DELAY_IN_MINUTES * 60000)
28+
public void cleanUpRepo() {
29+
Instant threshold = Instant.now().minus(5, ChronoUnit.MINUTES);
30+
logger.debug("Starting state machine cleanup. Repository size {}, removing machine older than {}", machineRepository.count(), threshold);
31+
machineRepository.removeMachinesOlderThan(threshold);
32+
logger.debug("Completed cleanup. Repository size {}", machineRepository.count());
33+
}
34+
}

src/main/java/ch/uzh/ifi/access/student/evaluation/process/EvalMachineFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class EvalMachineFactory {
1616
public static final String EXTENDED_VAR_SUBMISSION_ID = "submissionId";
1717
public static final String EXTENDED_VAR_NEXT_STEP = "nextStep";
1818
public static final String EXTENDED_VAR_NEXT_STEP_DELAY = "nextStepDelay";
19+
public static final String EXTENDED_VAR_COMPLETION_TIME = "completionTime";
1920

2021
public static StateMachine<EvalMachine.States, EvalMachine.Events> initSMForSubmission(String submissionId) throws Exception {
2122

@@ -57,6 +58,7 @@ public static StateMachine<EvalMachine.States, EvalMachine.Events> initSMForSubm
5758

5859
StateMachine<EvalMachine.States, EvalMachine.Events> machine = builder.build();
5960
machine.getExtendedState().getVariables().put(EXTENDED_VAR_SUBMISSION_ID, submissionId);
61+
machine.addStateListener(new StateMachineEventListener(machine));
6062
return machine;
6163
}
6264

src/main/java/ch/uzh/ifi/access/student/evaluation/process/EvalMachineRepoService.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.springframework.statemachine.StateMachine;
44
import org.springframework.stereotype.Service;
55

6+
import java.time.Instant;
67
import java.util.Map;
78
import java.util.concurrent.ConcurrentHashMap;
89

@@ -27,4 +28,15 @@ public void store(String key, StateMachine machine) {
2728
machines.put(key, machine);
2829
}
2930

31+
public long count() {
32+
return machines.size();
33+
}
34+
35+
public void removeMachinesOlderThan(Instant threshold) {
36+
machines.entrySet().removeIf(entry -> {
37+
StateMachine machine = entry.getValue();
38+
Instant completionTime = (Instant) machine.getExtendedState().getVariables().get(EvalMachineFactory.EXTENDED_VAR_COMPLETION_TIME);
39+
return completionTime.isBefore(threshold);
40+
});
41+
}
3042
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package ch.uzh.ifi.access.student.evaluation.process;
2+
3+
import org.springframework.statemachine.StateMachine;
4+
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
5+
import org.springframework.statemachine.state.State;
6+
7+
import java.time.Instant;
8+
9+
public class StateMachineEventListener
10+
extends StateMachineListenerAdapter<EvalMachine.States, EvalMachine.Events> {
11+
12+
private StateMachine<EvalMachine.States, EvalMachine.Events> machine;
13+
14+
public StateMachineEventListener(StateMachine<EvalMachine.States, EvalMachine.Events> machine) {
15+
this.machine = machine;
16+
}
17+
18+
@Override
19+
public void stateEntered(State<EvalMachine.States, EvalMachine.Events> state) {
20+
if (EvalMachine.States.FINISHED.equals(state.getId())) {
21+
machine.getExtendedState().getVariables().put(EvalMachineFactory.EXTENDED_VAR_COMPLETION_TIME, Instant.now());
22+
}
23+
}
24+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package ch.uzh.ifi.access.student.evaluation.process;
2+
3+
import org.assertj.core.api.Assertions;
4+
import org.junit.Test;
5+
import org.springframework.statemachine.StateMachine;
6+
7+
import java.time.Instant;
8+
import java.time.temporal.ChronoUnit;
9+
import java.util.UUID;
10+
11+
public class EvalMachineRepoServiceTest {
12+
13+
@Test
14+
public void cleanUpNoMachines() {
15+
EvalMachineRepoService repo = new EvalMachineRepoService();
16+
repo.removeMachinesOlderThan(Instant.now());
17+
}
18+
19+
@Test
20+
public void cleanUp() throws Exception {
21+
String id1 = UUID.randomUUID().toString();
22+
String id2 = UUID.randomUUID().toString();
23+
StateMachine<EvalMachine.States, EvalMachine.Events> m1 = EvalMachineFactory.initSMForSubmission("123");
24+
StateMachine<EvalMachine.States, EvalMachine.Events> m2 = EvalMachineFactory.initSMForSubmission("345");
25+
26+
m1.getExtendedState().getVariables().put(EvalMachineFactory.EXTENDED_VAR_COMPLETION_TIME, Instant.now().minus(1, ChronoUnit.MINUTES));
27+
m2.getExtendedState().getVariables().put(EvalMachineFactory.EXTENDED_VAR_COMPLETION_TIME, Instant.now().minus(30, ChronoUnit.MINUTES));
28+
29+
EvalMachineRepoService repo = new EvalMachineRepoService();
30+
repo.store(id1, m1);
31+
repo.store(id2, m2);
32+
33+
Assertions.assertThat(repo.get(id1)).isNotNull();
34+
Assertions.assertThat(repo.get(id2)).isNotNull();
35+
36+
Instant fiveMinutesAgo = Instant.now().minus(5, ChronoUnit.MINUTES);
37+
repo.removeMachinesOlderThan(fiveMinutesAgo);
38+
39+
Assertions.assertThat(repo.get(id1)).isNotNull();
40+
Assertions.assertThat(repo.get(id2)).isNull();
41+
}
42+
43+
@Test
44+
public void noMachinesToClean() throws Exception {
45+
String id1 = UUID.randomUUID().toString();
46+
String id2 = UUID.randomUUID().toString();
47+
StateMachine<EvalMachine.States, EvalMachine.Events> m1 = EvalMachineFactory.initSMForSubmission("123");
48+
StateMachine<EvalMachine.States, EvalMachine.Events> m2 = EvalMachineFactory.initSMForSubmission("345");
49+
50+
m1.getExtendedState().getVariables().put(EvalMachineFactory.EXTENDED_VAR_COMPLETION_TIME, Instant.now().minus(1, ChronoUnit.MINUTES));
51+
m2.getExtendedState().getVariables().put(EvalMachineFactory.EXTENDED_VAR_COMPLETION_TIME, Instant.now().minus(1, ChronoUnit.MINUTES));
52+
53+
EvalMachineRepoService repo = new EvalMachineRepoService();
54+
repo.store(id1, m1);
55+
repo.store(id2, m2);
56+
57+
Assertions.assertThat(repo.get(id1)).isNotNull();
58+
Assertions.assertThat(repo.get(id2)).isNotNull();
59+
60+
Instant fiveMinutesAgo = Instant.now().minus(5, ChronoUnit.MINUTES);
61+
repo.removeMachinesOlderThan(fiveMinutesAgo);
62+
63+
Assertions.assertThat(repo.get(id1)).isNotNull();
64+
Assertions.assertThat(repo.get(id2)).isNotNull();
65+
}
66+
}

0 commit comments

Comments
 (0)