SEBSERV-195 improved ping indicator for distributed setups
This commit is contained in:
parent
494c6a08ec
commit
3296b7c004
6 changed files with 16 additions and 35 deletions
|
@ -15,7 +15,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.ClientIndicator;
|
||||||
|
|
||||||
public abstract class AbstractClientIndicator implements ClientIndicator {
|
public abstract class AbstractClientIndicator implements ClientIndicator {
|
||||||
|
|
||||||
private static final long PERSISTENT_UPDATE_INTERVAL = 1 * Constants.SECOND_IN_MILLIS;
|
private static final long PERSISTENT_UPDATE_INTERVAL = Constants.SECOND_IN_MILLIS;
|
||||||
|
|
||||||
protected Long indicatorId;
|
protected Long indicatorId;
|
||||||
protected Long examId;
|
protected Long examId;
|
||||||
|
|
|
@ -15,26 +15,21 @@ import java.util.Set;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO;
|
||||||
|
|
||||||
public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
|
|
||||||
private static final int PING_COUNT_INTERVAL_FOR_PERSISTENT_UPDATE = 2;
|
private static final long INTERVAL_FOR_PERSISTENT_UPDATE = Constants.SECOND_IN_MILLIS;
|
||||||
|
|
||||||
private final Set<EventType> EMPTY_SET = Collections.unmodifiableSet(EnumSet.noneOf(EventType.class));
|
private final Set<EventType> EMPTY_SET = Collections.unmodifiableSet(EnumSet.noneOf(EventType.class));
|
||||||
|
|
||||||
protected final ClientEventDAO clientEventDAO;
|
protected final ClientEventDAO clientEventDAO;
|
||||||
|
|
||||||
protected long pingLatency;
|
private long lastUpdate = 0;
|
||||||
protected int pingCount = 0;
|
|
||||||
protected int pingNumber = 0;
|
|
||||||
|
|
||||||
protected ClientEventRecord pingRecord = null;
|
protected ClientEventRecord pingRecord = null;
|
||||||
|
|
||||||
protected AbstractPingIndicator(final ClientEventDAO clientEventDAO) {
|
protected AbstractPingIndicator(final ClientEventDAO clientEventDAO) {
|
||||||
|
@ -60,21 +55,19 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
|
|
||||||
public final void notifyPing(final long timestamp, final int pingNumber) {
|
public final void notifyPing(final long timestamp, final int pingNumber) {
|
||||||
final long now = DateTime.now(DateTimeZone.UTC).getMillis();
|
final long now = DateTime.now(DateTimeZone.UTC).getMillis();
|
||||||
this.pingLatency = now - timestamp;
|
|
||||||
super.currentValue = now;
|
super.currentValue = now;
|
||||||
this.pingCount++;
|
|
||||||
this.pingNumber = pingNumber;
|
|
||||||
super.lastPersistentUpdate = now;
|
super.lastPersistentUpdate = now;
|
||||||
|
|
||||||
if (!this.cachingEnabled &&
|
if (!this.cachingEnabled && this.pingRecord != null) {
|
||||||
this.pingCount > PING_COUNT_INTERVAL_FOR_PERSISTENT_UPDATE &&
|
|
||||||
this.pingRecord != null) {
|
|
||||||
|
|
||||||
// Update last ping time on persistent storage
|
// Update last ping time on persistent storage
|
||||||
this.pingRecord.setClientTime(timestamp);
|
final long millisecondsNow = System.currentTimeMillis();
|
||||||
this.pingRecord.setServerTime(Utils.getMillisecondsNow());
|
if (millisecondsNow - this.lastUpdate > INTERVAL_FOR_PERSISTENT_UPDATE) {
|
||||||
this.clientEventDAO.updatePingEvent(this.pingRecord);
|
this.pingRecord.setClientTime(timestamp);
|
||||||
this.pingCount = 0;
|
this.pingRecord.setServerTime(millisecondsNow);
|
||||||
|
this.clientEventDAO.updatePingEvent(this.pingRecord);
|
||||||
|
this.lastUpdate = millisecondsNow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,11 +76,6 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
return this.EMPTY_SET;
|
return this.EMPTY_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
public int getPingNumber() {
|
|
||||||
return this.pingNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract ClientEventRecord updateLogEvent(final long now);
|
public abstract ClientEventRecord updateLogEvent(final long now);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
server.address=localhost
|
server.address=localhost
|
||||||
server.port=8080
|
server.port=8090
|
||||||
|
|
||||||
sebserver.gui.http.external.scheme=http
|
sebserver.gui.http.external.scheme=http
|
||||||
sebserver.gui.entrypoint=/gui
|
sebserver.gui.entrypoint=/gui
|
||||||
sebserver.gui.webservice.protocol=http
|
sebserver.gui.webservice.protocol=http
|
||||||
sebserver.gui.webservice.address=localhost
|
sebserver.gui.webservice.address=localhost
|
||||||
sebserver.gui.webservice.port=8080
|
sebserver.gui.webservice.port=8090
|
||||||
sebserver.gui.webservice.apipath=/admin-api/v1
|
sebserver.gui.webservice.apipath=/admin-api/v1
|
||||||
# defines the polling interval that is used to poll the webservice for client connection data on a monitored exam page
|
# defines the polling interval that is used to poll the webservice for client connection data on a monitored exam page
|
||||||
sebserver.gui.webservice.poll-interval=1000
|
sebserver.gui.webservice.poll-interval=1000
|
||||||
|
|
|
@ -22,7 +22,7 @@ sebserver.webservice.clean-db-on-startup=false
|
||||||
|
|
||||||
# webservice configuration
|
# webservice configuration
|
||||||
sebserver.init.adminaccount.gen-on-init=false
|
sebserver.init.adminaccount.gen-on-init=false
|
||||||
sebserver.webservice.distributed=false
|
sebserver.webservice.distributed=true
|
||||||
sebserver.webservice.master.delay.threshold=10000
|
sebserver.webservice.master.delay.threshold=10000
|
||||||
sebserver.webservice.http.external.scheme=http
|
sebserver.webservice.http.external.scheme=http
|
||||||
sebserver.webservice.http.external.servername=localhost
|
sebserver.webservice.http.external.servername=localhost
|
||||||
|
|
|
@ -380,7 +380,7 @@ sebserver.quizdiscovery.action.import=Import as Exam
|
||||||
sebserver.quizdiscovery.quiz.import.out.dated=The Selected LMS exam is already finished and can't be imported
|
sebserver.quizdiscovery.quiz.import.out.dated=The Selected LMS exam is already finished and can't be imported
|
||||||
sebserver.quizdiscovery.action.details=Show LMS Exam Details
|
sebserver.quizdiscovery.action.details=Show LMS Exam Details
|
||||||
sebserver.quizdiscovery.quiz.import.existing.confirm=This course was already imported and importing it twice may lead to<br/> unexpected behavior within automated SEB restriction on LMS.<br/><br/> Do you want to import this course as exam anyway?
|
sebserver.quizdiscovery.quiz.import.existing.confirm=This course was already imported and importing it twice may lead to<br/> unexpected behavior within automated SEB restriction on LMS.<br/><br/> Do you want to import this course as exam anyway?
|
||||||
sebserver.quizdiscovery.quiz.import.existing=This course was already imported as an exam.<br/> You will find it in the Exam section.
|
sebserver.quizdiscovery.quiz.import.existing=This course was already imported as an exam.<br/>Please find it in the Exam section.
|
||||||
|
|
||||||
sebserver.quizdiscovery.quiz.details.title=LMS Exam Details
|
sebserver.quizdiscovery.quiz.details.title=LMS Exam Details
|
||||||
sebserver.quizdiscovery.quiz.details.institution=Institution
|
sebserver.quizdiscovery.quiz.details.institution=Institution
|
||||||
|
|
|
@ -38,7 +38,6 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientConnectionRe
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.ClientConnectionDataInternal;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.ClientConnectionDataInternal;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.ExamSessionCacheService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.ExamSessionCacheService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator.AbstractPingIndicator;
|
|
||||||
|
|
||||||
@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql", "classpath:data-test-additional.sql" })
|
@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql", "classpath:data-test-additional.sql" })
|
||||||
public class SebConnectionTest extends ExamAPIIntegrationTester {
|
public class SebConnectionTest extends ExamAPIIntegrationTester {
|
||||||
|
@ -468,20 +467,15 @@ public class SebConnectionTest extends ExamAPIIntegrationTester {
|
||||||
assertFalse(ccdi.indicatorValues.isEmpty());
|
assertFalse(ccdi.indicatorValues.isEmpty());
|
||||||
final IndicatorValue pingIndicator = ccdi.indicatorValues.iterator().next();
|
final IndicatorValue pingIndicator = ccdi.indicatorValues.iterator().next();
|
||||||
assertTrue(pingIndicator.getType() == IndicatorType.LAST_PING);
|
assertTrue(pingIndicator.getType() == IndicatorType.LAST_PING);
|
||||||
assertEquals("0", String.valueOf(((AbstractPingIndicator) pingIndicator).getPingNumber()));
|
|
||||||
|
|
||||||
super.sendPing(accessToken, connectionToken, 1);
|
super.sendPing(accessToken, connectionToken, 1);
|
||||||
Thread.sleep(200);
|
Thread.sleep(200);
|
||||||
assertEquals("1", String.valueOf(((AbstractPingIndicator) pingIndicator).getPingNumber()));
|
|
||||||
super.sendPing(accessToken, connectionToken, 2);
|
super.sendPing(accessToken, connectionToken, 2);
|
||||||
Thread.sleep(200);
|
Thread.sleep(200);
|
||||||
assertEquals("2", String.valueOf(((AbstractPingIndicator) pingIndicator).getPingNumber()));
|
|
||||||
super.sendPing(accessToken, connectionToken, 3);
|
super.sendPing(accessToken, connectionToken, 3);
|
||||||
Thread.sleep(200);
|
Thread.sleep(200);
|
||||||
assertEquals("3", String.valueOf(((AbstractPingIndicator) pingIndicator).getPingNumber()));
|
|
||||||
super.sendPing(accessToken, connectionToken, 5);
|
super.sendPing(accessToken, connectionToken, 5);
|
||||||
Thread.sleep(200);
|
Thread.sleep(200);
|
||||||
assertEquals("5", String.valueOf(((AbstractPingIndicator) pingIndicator).getPingNumber()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -531,7 +525,6 @@ public class SebConnectionTest extends ExamAPIIntegrationTester {
|
||||||
assertFalse(ccdi.indicatorValues.isEmpty());
|
assertFalse(ccdi.indicatorValues.isEmpty());
|
||||||
final IndicatorValue pingIndicator = ccdi.indicatorValues.iterator().next();
|
final IndicatorValue pingIndicator = ccdi.indicatorValues.iterator().next();
|
||||||
assertTrue(pingIndicator.getType() == IndicatorType.LAST_PING);
|
assertTrue(pingIndicator.getType() == IndicatorType.LAST_PING);
|
||||||
assertEquals("0", String.valueOf(((AbstractPingIndicator) pingIndicator).getPingNumber()));
|
|
||||||
|
|
||||||
MockHttpServletResponse sendEvent = super.sendEvent(
|
MockHttpServletResponse sendEvent = super.sendEvent(
|
||||||
accessToken,
|
accessToken,
|
||||||
|
|
Loading…
Add table
Reference in a new issue