SEBSERV-300 fixed by check the last follow-up id of the config from

cache. If not the same, reolad the cache.
This commit is contained in:
anhefti 2022-04-27 13:40:25 +02:00
parent bc1026a6b7
commit 0f8910bb3f
7 changed files with 97 additions and 4 deletions

View file

@ -105,4 +105,10 @@ public interface ConfigurationDAO extends EntityDAO<Configuration, Configuration
* @return the last version of configuration */
Result<Configuration> getConfigurationLastStableVersion(Long configNodeId);
/** Use this to get the follow-up configuration identifer for a specified configuration node.
*
* @param configurationNode ConfigurationNode to get the current follow-up configuration from
* @return the current follow-up configuration identifier */
Result<Long> getFollowupConfigurationId(Long configNodeId);
}

View file

@ -133,8 +133,24 @@ public class ConfigurationDAOImpl implements ConfigurationDAO {
.build()
.execute()
.stream()
.collect(Utils.toSingleton())).flatMap(ConfigurationDAOImpl::toDomainModel);
.collect(Utils.toSingleton()))
.flatMap(ConfigurationDAOImpl::toDomainModel);
}
@Override
@Transactional(readOnly = true)
public Result<Long> getFollowupConfigurationId(final Long configNodeId) {
return Result.tryCatch(() -> this.configurationRecordMapper.selectIdsByExample()
.where(
ConfigurationRecordDynamicSqlSupport.configurationNodeId,
isEqualTo(configNodeId))
.and(
ConfigurationRecordDynamicSqlSupport.followup,
isEqualTo(BooleanUtils.toInteger(true)))
.build()
.execute()
.stream()
.collect(Utils.toSingleton()));
}
@Override

View file

@ -35,6 +35,13 @@ public interface ExamConfigService {
* @throws FieldValidationException on validation exception */
void validate(ConfigurationTableValues tableValue) throws FieldValidationException;
/** Get the follow-up configuration identifier for a given configuration node identifier.
*
* @param examConfigNodeId the exam configuration node identifier
* @return Result refer to the follow-up configuration identifier of the given config node or to an error when
* happened */
Result<Long> getFollowupConfigurationId(final Long examConfigNodeId);
/** Used to export a specified SEB Exam Configuration as plain XML
* This exports the values of the follow-up configuration defined by a given
* ConfigurationNode (configurationNodeId)

View file

@ -128,6 +128,10 @@ public class ExamConfigServiceImpl implements ExamConfigService {
}
}
public Result<Long> getFollowupConfigurationId(final Long examConfigNodeId) {
return this.configurationDAO.getFollowupConfigurationId(examConfigNodeId);
}
@Override
public void exportPlainXML(
final OutputStream out,

View file

@ -173,8 +173,12 @@ public class ExamSessionCacheService {
byteOut,
institutionId,
examId);
final Long followupId = this.sebExamConfigService
.getFollowupConfigurationId(configId)
.onError(error -> log.error("Failed to get follow-up id for config node: {}", configId, error))
.getOr(-1L);
return new InMemorySEBConfig(configId, examId, byteOut.toByteArray());
return new InMemorySEBConfig(configId, followupId, examId, byteOut.toByteArray());
} catch (final Exception e) {
log.error("Unexpected error while getting default exam configuration for running exam; {}", examId, e);
@ -182,6 +186,19 @@ public class ExamSessionCacheService {
}
}
public boolean isUpToDate(final InMemorySEBConfig inMemorySEBConfig) {
try {
final Long followupId = this.sebExamConfigService
.getFollowupConfigurationId(inMemorySEBConfig.configId)
.getOrThrow();
return followupId.equals(inMemorySEBConfig.follwupId);
} catch (final Exception e) {
log.error("Failed to check if InMemorySEBConfig is up to date for: {}", inMemorySEBConfig);
return true;
}
}
@CacheEvict(
cacheNames = CACHE_NAME_SEB_CONFIG_EXAM,
key = "#examId")

View file

@ -285,7 +285,7 @@ public class ExamSessionServiceImpl implements ExamSessionService {
log.trace("Trying to get exam from InMemorySEBConfig");
}
final InMemorySEBConfig sebConfigForExam = this.examSessionCacheService
InMemorySEBConfig sebConfigForExam = this.examSessionCacheService
.getDefaultSEBConfigForExam(connection.examId, institutionId);
if (sebConfigForExam == null) {
@ -293,6 +293,23 @@ public class ExamSessionServiceImpl implements ExamSessionService {
return;
}
// for distributed setups check if cached config is still up to date. Flush and reload if not.
if (this.distributedSetup && !this.examSessionCacheService.isUpToDate(sebConfigForExam)) {
if (log.isDebugEnabled()) {
log.debug("Detected new version of exam configuration for exam {} ...flush cache", connection.examId);
}
this.examSessionCacheService.evictDefaultSEBConfig(connection.examId);
sebConfigForExam = this.examSessionCacheService
.getDefaultSEBConfigForExam(connection.examId, institutionId);
}
if (sebConfigForExam == null) {
log.error("Failed to get and cache InMemorySEBConfig for connection: {}", connection);
return;
}
try {
if (log.isTraceEnabled()) {

View file

@ -11,12 +11,19 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
public final class InMemorySEBConfig {
public final Long configId;
public final Long follwupId;
public final Long examId;
private final byte[] data;
protected InMemorySEBConfig(final Long configId, final Long examId, final byte[] data) {
protected InMemorySEBConfig(
final Long configId,
final Long follwupId,
final Long examId,
final byte[] data) {
super();
this.configId = configId;
this.follwupId = follwupId;
this.examId = examId;
this.data = data;
}
@ -39,6 +46,7 @@ public final class InMemorySEBConfig {
int result = 1;
result = prime * result + ((this.configId == null) ? 0 : this.configId.hashCode());
result = prime * result + ((this.examId == null) ? 0 : this.examId.hashCode());
result = prime * result + ((this.follwupId == null) ? 0 : this.follwupId.hashCode());
return result;
}
@ -61,7 +69,25 @@ public final class InMemorySEBConfig {
return false;
} else if (!this.examId.equals(other.examId))
return false;
if (this.follwupId == null) {
if (other.follwupId != null)
return false;
} else if (!this.follwupId.equals(other.follwupId))
return false;
return true;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("InMemorySEBConfig [configId=");
builder.append(this.configId);
builder.append(", follwupId=");
builder.append(this.follwupId);
builder.append(", examId=");
builder.append(this.examId);
builder.append("]");
return builder.toString();
}
}