SEBSERV-266

This commit is contained in:
anhefti 2022-02-01 10:56:53 +01:00
parent a732b0c871
commit 8355e93d36
6 changed files with 100 additions and 32 deletions

View file

@ -9,12 +9,15 @@
package ch.ethz.seb.sebserver.webservice;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.MigrationInfo;
import org.flywaydb.core.api.MigrationInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.SEBServerInit;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.WebserviceInfoDAO;
@ -27,6 +30,8 @@ public class SEBServerMigrationStrategy implements FlywayMigrationStrategy {
private final boolean cleanDBOnStartup;
private final WebserviceInfo webserviceInfo;
private final WebserviceInfoDAO webserviceInfoDAO;
private Flyway flyway;
private final boolean migrationApplied = false;
public SEBServerMigrationStrategy(
final WebserviceInfo webserviceInfo,
@ -40,31 +45,83 @@ public class SEBServerMigrationStrategy implements FlywayMigrationStrategy {
@Override
public void migrate(final Flyway flyway) {
this.flyway = flyway;
}
public void applyMigration() {
final String webserviceUUID = this.webserviceInfo.getWebserviceUUID();
if (this.migrationApplied) {
log.warn("Migration already applied for this webservice: {}", webserviceUUID);
return;
}
try {
// If we are in a distributed setup only apply migration task if this is the master service
// or if there was no data base initialization yet at all.
if (this.webserviceInfo.isDistributed()) {
if (this.webserviceInfoDAO.isInitialized()) {
final boolean isMaster = this.webserviceInfoDAO.isMaster(this.webserviceInfo.getWebserviceUUID());
if (!isMaster) {
log.info(
"Skip migration task since this is not a master instance: {}",
this.webserviceInfo.getWebserviceUUID());
SEBServerInit.INIT_LOGGER.info("----> ** Migration check START **");
SEBServerInit.INIT_LOGGER.info("----> Check database status");
return;
final MigrationInfoService info = this.flyway.info();
if (SEBServerInit.INIT_LOGGER.isDebugEnabled()) {
SEBServerInit.INIT_LOGGER.debug("----> ** Migration Info **");
SEBServerInit.INIT_LOGGER.debug("----> {}", info);
}
final MigrationInfo[] pendingMigrations = info.pending();
if (pendingMigrations != null && pendingMigrations.length > 0) {
SEBServerInit.INIT_LOGGER.info("----> Found pending migrations: {}", pendingMigrations.length);
// If we are in a distributed setup only apply migration task if this is the master service
// or if there was no data base initialization yet at all.
if (this.webserviceInfo.isDistributed()) {
SEBServerInit.INIT_LOGGER.info("----> This is distributed setup, check master...");
if (this.webserviceInfoDAO.isInitialized()) {
final boolean isMaster = this.webserviceInfoDAO.isMaster(webserviceUUID);
if (!isMaster) {
SEBServerInit.INIT_LOGGER.info(
"----> Skip migration task since this is not a master instance: {}",
this.webserviceInfo.getWebserviceUUID());
} else {
doMigration();
}
}
} else {
doMigration();
}
} else {
SEBServerInit.INIT_LOGGER.info("----> ");
SEBServerInit.INIT_LOGGER.info("----> No pending migrations found. Last migration --> {} --> {}",
info.current().getVersion(),
info.current().getDescription());
}
if (this.cleanDBOnStartup) {
flyway.clean();
}
flyway.migrate();
SEBServerInit.INIT_LOGGER.info("----> ** Migration check END **");
} catch (final Exception e) {
log.error("Failed to apply migration task: ", e);
}
}
private void doMigration() {
SEBServerInit.INIT_LOGGER.info("----> *** Start migration ***");
if (this.cleanDBOnStartup) {
SEBServerInit.INIT_LOGGER
.info("----> !!! Cleanup database as it was set on sebserver.webservice.clean-db-on-startup !!!");
this.flyway.clean();
}
this.flyway.migrate();
final MigrationInfoService info = this.flyway.info();
SEBServerInit.INIT_LOGGER.info("----> Migration finished, new current version is: {} --> {}",
info.current().getVersion(),
info.current().getDescription());
SEBServerInit.INIT_LOGGER.info("----> *** End migration ***");
}
}

View file

@ -40,6 +40,7 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
private final ApplicationEventPublisher applicationEventPublisher;
private final WebserviceInfoDAO webserviceInfoDAO;
private final DBIntegrityChecker dbIntegrityChecker;
private final SEBServerMigrationStrategy sebServerMigrationStrategy;
protected WebserviceInit(
final SEBServerInit sebServerInit,
@ -48,7 +49,8 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
final ApplicationEventPublisher applicationEventPublisher,
final WebserviceInfoDAO webserviceInfoDAO,
final DBIntegrityChecker dbIntegrityChecker,
final ApplicationContext applicationContext) {
final ApplicationContext applicationContext,
final SEBServerMigrationStrategy sebServerMigrationStrategy) {
this.applicationContext = applicationContext;
this.sebServerInit = sebServerInit;
@ -58,7 +60,7 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
this.applicationEventPublisher = applicationEventPublisher;
this.webserviceInfoDAO = webserviceInfoDAO;
this.dbIntegrityChecker = dbIntegrityChecker;
this.sebServerMigrationStrategy = sebServerMigrationStrategy;
}
public ApplicationContext getApplicationContext() {
@ -87,6 +89,11 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
SEBServerInit.INIT_LOGGER.error("----> Failed to register webservice: ", e);
}
// Apply migration if needed and possible
SEBServerInit.INIT_LOGGER.info("----> ");
this.sebServerMigrationStrategy.applyMigration();
SEBServerInit.INIT_LOGGER.info("----> ");
SEBServerInit.INIT_LOGGER.info("----> ");
SEBServerInit.INIT_LOGGER.info("----> Initialize Services...");
SEBServerInit.INIT_LOGGER.info("----> ");

View file

@ -119,8 +119,7 @@ public class WebserviceInfoDAOImpl implements WebserviceInfoDAO {
final long now = Utils.getMillisecondsNow();
final long lastUpdateSince = now - masterRec.getUpdateTime();
if (lastUpdateSince > this.masterDelayTimeThreshold || this.forceMaster) {
forceMaster(uuid, masterRec.getUuid(), masterRec.getId());
return true;
return forceMaster(uuid, masterRec.getUuid(), masterRec.getId());
}
}
} else {
@ -136,13 +135,14 @@ public class WebserviceInfoDAOImpl implements WebserviceInfoDAO {
}
}
private void forceMaster(final String uuid, final String otherUUID, final Long otherId) {
private boolean forceMaster(final String uuid, final String otherUUID, final Long otherId) {
log.info("Change webservice master form uuid: {} to uuid: {}", otherUUID, uuid);
log.info("Change webservice master from uuid: {} to uuid: {}", otherUUID, uuid);
this.webserviceServerInfoRecordMapper.updateByPrimaryKeySelective(
new WebserviceServerInfoRecord(otherId, null, null, 0, 0L));
setMasterTo(uuid);
return setMasterTo(uuid);
}
private boolean setMasterTo(final String uuid) {
@ -156,9 +156,7 @@ public class WebserviceInfoDAOImpl implements WebserviceInfoDAO {
.execute();
if (entries == null || entries.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("The webservice with uuid: {} is not registered and cannot become a master", uuid);
}
log.warn("The webservice with uuid: {} is not registered and cannot become a master", uuid);
return false;
}

View file

@ -88,10 +88,11 @@ class ExamSessionControlTask implements DisposableBean {
SEBServerInit.INIT_LOGGER.info(
"------> Activate SEB lost-ping-event update background task on a fix rate of: {} milliseconds",
this.pingUpdateRate);
}
@Scheduled(cron = "${sebserver.webservice.api.exam.update-interval:1 * * * * *}")
@Scheduled(
fixedDelayString = "${sebserver.webservice.api.exam.update-interval:60000}",
initialDelay = 30000)
public void examRunUpdateTask() {
if (!this.webserviceInfoDAO.isMaster(this.webserviceInfo.getWebserviceUUID())) {
@ -109,7 +110,9 @@ class ExamSessionControlTask implements DisposableBean {
this.examDAO.releaseAgedLocks();
}
@Scheduled(fixedDelayString = "${sebserver.webservice.api.seb.lostping.update:5000}")
@Scheduled(
fixedDelayString = "${sebserver.webservice.api.seb.lostping.update:5000}",
initialDelay = 30000)
public void examSessionUpdateTask() {
this.sebClientConnectionService.updatePingEvents();
@ -122,7 +125,9 @@ class ExamSessionControlTask implements DisposableBean {
this.examProcotringRoomService.updateProctoringCollectingRooms();
}
@Scheduled(fixedRateString = "${sebserver.webservice.api.exam.session-cleanup:30000}")
@Scheduled(
fixedRateString = "${sebserver.webservice.api.exam.session-cleanup:30000}",
initialDelay = 30000)
public void examSessionCleanupTask() {
if (!this.webserviceInfoDAO.isMaster(this.webserviceInfo.getWebserviceUUID())) {

View file

@ -25,8 +25,8 @@ sebserver.webservice.clean-db-on-startup=false
# webservice configuration
sebserver.init.adminaccount.gen-on-init=false
sebserver.webservice.distributed=true
sebserver.webservice.master.delay.threshold=10000
sebserver.webservice.distributed=false
#sebserver.webservice.master.delay.threshold=10000
sebserver.webservice.http.external.scheme=http
sebserver.webservice.http.external.servername=localhost
sebserver.webservice.http.external.port=${server.port}

View file

@ -7,6 +7,7 @@ server.port=8080
server.servlet.context-path=/
server.tomcat.uri-encoding=UTF-8
logging.level.ROOT=INFO
logging.level.ch=INFO
logging.level.ch.ethz.seb.sebserver.webservice.datalayer=INFO
logging.level.org.springframework.cache=INFO
@ -19,7 +20,7 @@ logging.level.ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicat
#logging.level.ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper=DEBUG
#logging.level.ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordMapper=DEBUG
#logging.level.ch.ethz.seb.sebserver.webservice.weblayer.api.ExamAPI_V1_Controller=TRACE
logging.level.com.zaxxer.hikari=DEBUG
logging.level.com.zaxxer.hikari=INFO
sebserver.http.client.connect-timeout=15000
sebserver.http.client.connection-request-timeout=10000