minor fixes in error handling and running exam update

This commit is contained in:
anhefti 2022-05-03 08:57:45 +02:00
parent a74d4c6e22
commit e5ca068ccb
8 changed files with 40 additions and 34 deletions

View file

@ -50,13 +50,11 @@ public final class CircuitBreaker<T> {
private static final Logger log = LoggerFactory.getLogger(CircuitBreaker.class);
public static final String OPEN_CIRCUIT_BREAKER_EXCEPTION = "Open CircuitBreaker";
public static final int DEFAULT_MAX_FAILING_ATTEMPTS = 5;
public static final long DEFAULT_MAX_BLOCKING_TIME = Constants.MINUTE_IN_MILLIS;
public static final long DEFAULT_TIME_TO_RECOVER = Constants.MINUTE_IN_MILLIS * 10;
public static final RuntimeException OPEN_STATE_EXCEPTION =
new RuntimeException("Open CircuitBreaker");
public enum State {
CLOSED,
HALF_OPEN,
@ -243,7 +241,7 @@ public final class CircuitBreaker<T> {
return protectedRun(supplier);
}
return Result.ofError(OPEN_STATE_EXCEPTION);
return Result.ofError(new RuntimeException(OPEN_CIRCUIT_BREAKER_EXCEPTION));
}
private Result<T> attempt(final Supplier<T> supplier) {

View file

@ -63,7 +63,7 @@ public final class UpdateErrorHandler implements Function<Exception, Boolean> {
@Override
public Boolean apply(final Exception error) {
this.errors++;
log.error("Failed to update server push: {}", error.getMessage());
log.error("Failed to update server push: {}", error.getMessage(), error);
if (this.errors > 5) {
checkUserSession();
}

View file

@ -198,6 +198,9 @@ public class ClientConnectionDetails {
this.connectionData.getIndicatorValues()
.forEach(indValue -> {
final IndicatorData indData = this.indicatorMapping.get(indValue.getIndicatorId());
if (indData == null) {
return;
}
final double value = indValue.getValue();
final String displayValue = IndicatorValue.getDisplayValue(indValue, indData.indicator.type);

View file

@ -496,8 +496,9 @@ public final class ClientConnectionTable implements FullPageMonitoringGUIUpdate
for (int i = 0; i < this.connectionData.indicatorValues.size(); i++) {
final IndicatorValue indicatorValue = this.connectionData.indicatorValues.get(i);
final IndicatorData indicatorData =
ClientConnectionTable.this.indicatorMapping.get(indicatorValue.getIndicatorId());
final IndicatorData indicatorData = ClientConnectionTable.this.indicatorMapping
.get(indicatorValue.getIndicatorId());
if (indicatorData == null) {
continue;
}

View file

@ -109,7 +109,11 @@ public class ExamDAOImpl implements ExamDAO {
final QuizData quizData = this.lmsAPIService
.getLmsAPITemplate(record.getLmsSetupId())
.flatMap(template -> template.getQuiz(record.getExternalId()))
.getOrThrow();
.onError(error -> log.error(
"Failed to load quiz data for exam: {} error: {}",
examId,
error.getMessage()))
.getOr(null);
return toDomainModel(record, quizData, null, true);
});
}
@ -791,26 +795,11 @@ public class ExamDAOImpl implements ExamDAO {
log.info("Try to recover quiz data for Moodle quiz with internal identifier: {}", externalId);
// get additional quiz name attribute
final AdditionalAttributeRecord additionalAttribute =
this.additionalAttributeRecordMapper.selectByExample()
.where(
AdditionalAttributeRecordDynamicSqlSupport.entityType,
SqlBuilder.isEqualTo(EntityType.EXAM.name()))
.and(
AdditionalAttributeRecordDynamicSqlSupport.entityId,
SqlBuilder.isEqualTo(record.getId()))
.and(
AdditionalAttributeRecordDynamicSqlSupport.name,
SqlBuilder.isEqualTo(QuizData.QUIZ_ATTR_NAME))
.build()
.execute()
.stream()
.findAny()
.orElse(null);
if (additionalAttribute != null) {
// get former quiz name attribute
final String formerName = getFormerName(record.getId());
if (formerName != null) {
log.debug("Found additional quiz name attribute: {}", additionalAttribute);
log.debug("Found formerName quiz name: {}", formerName);
// get the course name identifier
final String shortname = MoodleCourseAccess.getShortname(externalId);
@ -827,7 +816,7 @@ public class ExamDAOImpl implements ExamDAO {
final String qShortName = MoodleCourseAccess.getShortname(quiz.id);
return qShortName != null && qShortName.equals(shortname);
})
.filter(quiz -> additionalAttribute.getValue().equals(quiz.name))
.filter(quiz -> formerName.equals(quiz.name))
.findAny()
.get())
.getOrThrow();
@ -851,7 +840,7 @@ public class ExamDAOImpl implements ExamDAO {
}
}
} catch (final Exception e) {
log.warn("Failed to try to recover from Moodle quiz restore: {}", e.getMessage());
log.debug("Failed to try to recover from Moodle quiz restore: {}", e.getMessage());
}
return null;
}

View file

@ -156,7 +156,7 @@ public class ExamSessionControlTask implements DisposableBean {
final Map<Long, String> updated = this.examDAO.allForRunCheck()
.getOrThrow()
.stream()
.filter(exam -> exam.startTime.minus(this.examTimePrefix).isBefore(now))
.filter(exam -> exam.startTime != null && exam.startTime.minus(this.examTimePrefix).isBefore(now))
.filter(exam -> exam.endTime == null || exam.endTime.plus(this.examTimeSuffix).isAfter(now))
.flatMap(exam -> Result.skipOnError(this.examUpdateHandler.setRunning(exam, updateId)))
.collect(Collectors.toMap(Exam::getId, Exam::getName));

View file

@ -245,12 +245,20 @@ public class ExamSessionServiceImpl implements ExamSessionService {
.putIfAbsent(Exam.FILTER_ATTR_ACTIVE, Constants.TRUE_STRING)
.putIfAbsent(Exam.FILTER_ATTR_STATUS, ExamStatus.RUNNING.name());
// NOTE: we evict the exam from the cache (if present) to ensure user is seeing always the current state of the Exam
return this.examDAO.allMatching(filterMap, predicate)
.map(col -> col.stream()
.map(exam -> {
this.examSessionCacheService.evict(exam);
return this.examSessionCacheService.getRunningExam(exam.id);
final Exam runningExam = this.examSessionCacheService.getRunningExam(exam.id);
if (runningExam == null) {
return null;
}
if (!isUpToDate(exam, runningExam)) {
// If the cached exam-quiz data differs from the one of the currently loaded exam, cache is updated
this.examSessionCacheService.evict(exam);
return this.examSessionCacheService.getRunningExam(exam.id);
} else {
return runningExam;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList()));
@ -514,4 +522,11 @@ public class ExamSessionServiceImpl implements ExamSessionService {
}
}
private boolean isUpToDate(final Exam exam, final Exam runningExam) {
return Objects.equals(exam.lastModified, runningExam.lastModified)
&& Objects.equals(exam.startTime, runningExam.startTime)
&& Objects.equals(exam.endTime, runningExam.endTime)
&& Objects.equals(exam.name, runningExam.name);
}
}

View file

@ -73,7 +73,7 @@ public class CircuitBreakerTest {
Thread.sleep(100);
result = circuitBreaker.protectedRun(tester); // 10. call...
assertEquals(State.OPEN, circuitBreaker.getState());
assertEquals(CircuitBreaker.OPEN_STATE_EXCEPTION, result.getError());
assertEquals(CircuitBreaker.OPEN_CIRCUIT_BREAKER_EXCEPTION, result.getError().getMessage());
// wait time to recover
Thread.sleep(1000);