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
	
	 anhefti
						anhefti