ping indicator performance
This commit is contained in:
parent
43578d3e1c
commit
36cd75218e
7 changed files with 97 additions and 45 deletions
|
@ -503,6 +503,9 @@ public final class ClientConnectionTable {
|
|||
final IndicatorValue indicatorValue = this.connectionData.indicatorValues.get(i);
|
||||
final IndicatorData indicatorData =
|
||||
ClientConnectionTable.this.indicatorMapping.get(indicatorValue.getType());
|
||||
if (indicatorData == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.connectionData.clientConnection.status.establishedStatus) {
|
||||
final String value = (indicatorData.indicator.type.showOnlyInActiveState)
|
||||
|
|
|
@ -14,6 +14,9 @@ import java.util.Collections;
|
|||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||
|
@ -23,7 +26,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.ClientIndicator;
|
|||
|
||||
public class ClientConnectionDataInternal extends ClientConnectionData {
|
||||
|
||||
final Collection<AbstractPingIndicator> pingMappings;
|
||||
private static final Logger log = LoggerFactory.getLogger(ClientConnectionDataInternal.class);
|
||||
|
||||
final EnumMap<EventType, Collection<ClientIndicator>> indicatorMapping;
|
||||
|
||||
PingIntervalClientIndicator pingIndicator = null;
|
||||
|
@ -35,17 +39,13 @@ public class ClientConnectionDataInternal extends ClientConnectionData {
|
|||
super(clientConnection, clientIndicators);
|
||||
|
||||
this.indicatorMapping = new EnumMap<>(EventType.class);
|
||||
this.pingMappings = new ArrayList<>();
|
||||
for (final ClientIndicator clientIndicator : clientIndicators) {
|
||||
if (clientIndicator instanceof AbstractPingIndicator) {
|
||||
if (clientIndicator instanceof PingIntervalClientIndicator) {
|
||||
this.pingIndicator = (PingIntervalClientIndicator) clientIndicator;
|
||||
if (!this.pingIndicator.hidden) {
|
||||
this.pingMappings.add((AbstractPingIndicator) clientIndicator);
|
||||
}
|
||||
} else {
|
||||
this.pingMappings.add((AbstractPingIndicator) clientIndicator);
|
||||
if (clientIndicator instanceof PingIntervalClientIndicator) {
|
||||
if (this.pingIndicator != null) {
|
||||
log.error("Currently only one ping indicator is allowed: {}", clientIndicator);
|
||||
continue;
|
||||
}
|
||||
this.pingIndicator = (PingIntervalClientIndicator) clientIndicator;
|
||||
}
|
||||
for (final EventType eventType : clientIndicator.observedEvents()) {
|
||||
this.indicatorMapping
|
||||
|
@ -55,6 +55,12 @@ public class ClientConnectionDataInternal extends ClientConnectionData {
|
|||
}
|
||||
}
|
||||
|
||||
public final void notifyPing(final long timestamp, final int pingNumber) {
|
||||
if (this.pingIndicator != null) {
|
||||
this.pingIndicator.notifyPing(timestamp, pingNumber);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<ClientIndicator> getIndicatorMapping(final EventType eventType) {
|
||||
if (!this.indicatorMapping.containsKey(eventType)) {
|
||||
return Collections.emptyList();
|
||||
|
|
|
@ -59,8 +59,7 @@ public class DistributedServerPingHandler implements PingHandlingStrategy {
|
|||
this.examSessionCacheService.getActiveClientConnection(connectionToken);
|
||||
|
||||
if (activeClientConnection != null) {
|
||||
activeClientConnection.pingMappings
|
||||
.forEach(pingIndicator -> pingIndicator.notifyPing(timestamp, pingNumber));
|
||||
activeClientConnection.notifyPing(timestamp, pingNumber);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,7 @@ public class SingleServerPingHandler implements PingHandlingStrategy {
|
|||
this.examSessionCacheService.getActiveClientConnection(connectionToken);
|
||||
|
||||
if (activeClientConnection != null) {
|
||||
activeClientConnection.pingMappings
|
||||
.forEach(pingIndicator -> pingIndicator.notifyPing(timestamp, pingNumber));
|
||||
activeClientConnection.notifyPing(timestamp, pingNumber);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -274,43 +274,63 @@ public class ExamAPI_V1_Controller {
|
|||
.ok()
|
||||
.build();
|
||||
|
||||
// @RequestMapping(
|
||||
// path = API.EXAM_API_PING_ENDPOINT,
|
||||
// method = RequestMethod.POST,
|
||||
// consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
// produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
// public CompletableFuture<ResponseEntity<String>> ping(
|
||||
// @RequestHeader(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||
// @RequestParam(name = API.EXAM_API_PING_TIMESTAMP, required = true) final long timestamp,
|
||||
// @RequestParam(name = API.EXAM_API_PING_NUMBER, required = false) final int pingNumber) {
|
||||
//
|
||||
// return CompletableFuture.supplyAsync(
|
||||
// () -> {
|
||||
// final String notifyPing = this.sebClientConnectionService
|
||||
// .notifyPing(connectionToken, timestamp, pingNumber);
|
||||
// if (notifyPing == null) {
|
||||
// return EMPTY_PING_RESPONSE;
|
||||
// }
|
||||
//
|
||||
// return ResponseEntity
|
||||
// .ok()
|
||||
// .body(notifyPing);
|
||||
// },
|
||||
// this.executor);
|
||||
// }
|
||||
|
||||
@RequestMapping(
|
||||
path = API.EXAM_API_PING_ENDPOINT,
|
||||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public CompletableFuture<ResponseEntity<String>> ping(
|
||||
public ResponseEntity<String> ping(
|
||||
@RequestHeader(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||
@RequestParam(name = API.EXAM_API_PING_TIMESTAMP, required = true) final long timestamp,
|
||||
@RequestParam(name = API.EXAM_API_PING_NUMBER, required = false) final int pingNumber) {
|
||||
|
||||
return CompletableFuture.supplyAsync(
|
||||
() -> {
|
||||
final String notifyPing = this.sebClientConnectionService
|
||||
.notifyPing(connectionToken, timestamp, pingNumber);
|
||||
if (notifyPing == null) {
|
||||
return EMPTY_PING_RESPONSE;
|
||||
}
|
||||
final String instruction = this.sebClientConnectionService
|
||||
.notifyPing(connectionToken, timestamp, pingNumber);
|
||||
|
||||
return ResponseEntity
|
||||
.ok()
|
||||
.body(notifyPing);
|
||||
},
|
||||
this.executor);
|
||||
if (instruction == null) {
|
||||
return EMPTY_PING_RESPONSE;
|
||||
}
|
||||
|
||||
return ResponseEntity
|
||||
.ok()
|
||||
.body(instruction);
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.EXAM_API_EVENT_ENDPOINT,
|
||||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public CompletableFuture<Void> event(
|
||||
public void event(
|
||||
@RequestHeader(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken,
|
||||
@RequestBody(required = true) final ClientEvent event) {
|
||||
|
||||
return CompletableFuture.runAsync(
|
||||
() -> this.sebClientConnectionService
|
||||
.notifyClientEvent(connectionToken, event),
|
||||
this.executor);
|
||||
this.sebClientConnectionService
|
||||
.notifyClientEvent(connectionToken, event);
|
||||
}
|
||||
|
||||
private Long getInstitutionId(final Principal principal) {
|
||||
|
|
|
@ -16,9 +16,11 @@ import ch.ethz.seb.sebserver.gbl.api.API;
|
|||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Pair;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.IndicatorRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
|
@ -27,6 +29,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionServic
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
|
||||
|
||||
@WebServiceProfile
|
||||
|
@ -35,6 +38,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
|
|||
public class IndicatorController extends EntityController<Indicator, Indicator> {
|
||||
|
||||
private final ExamDAO examDao;
|
||||
private final ExamSessionService examSessionService;
|
||||
|
||||
protected IndicatorController(
|
||||
final AuthorizationService authorization,
|
||||
|
@ -43,7 +47,8 @@ public class IndicatorController extends EntityController<Indicator, Indicator>
|
|||
final ExamDAO examDao,
|
||||
final UserActivityLogDAO userActivityLogDAO,
|
||||
final PaginationService paginationService,
|
||||
final BeanValidationService beanValidationService) {
|
||||
final BeanValidationService beanValidationService,
|
||||
final ExamSessionService examSessionService) {
|
||||
|
||||
super(authorization,
|
||||
bulkActionService,
|
||||
|
@ -53,6 +58,7 @@ public class IndicatorController extends EntityController<Indicator, Indicator>
|
|||
beanValidationService);
|
||||
|
||||
this.examDao = examDao;
|
||||
this.examSessionService = examSessionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,4 +101,31 @@ public class IndicatorController extends EntityController<Indicator, Indicator>
|
|||
return EntityType.EXAM;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<Indicator> notifyCreated(final Indicator entity) {
|
||||
flushExamSessionCaches(entity);
|
||||
return super.notifyCreated(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<Indicator> notifySaved(final Indicator entity) {
|
||||
flushExamSessionCaches(entity);
|
||||
return super.notifySaved(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<Pair<Indicator, EntityProcessingReport>> notifyDeleted(
|
||||
final Pair<Indicator, EntityProcessingReport> pair) {
|
||||
|
||||
flushExamSessionCaches(pair.a);
|
||||
return super.notifyDeleted(pair);
|
||||
}
|
||||
|
||||
private void flushExamSessionCaches(final Indicator entity) {
|
||||
if (this.examSessionService.isExamRunning(entity.examId)) {
|
||||
this.examSessionService.flushCache(this.examSessionService.getRunningExam(entity.examId).getOrThrow());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -259,12 +259,8 @@ public abstract class ExamAPIIntegrationTester {
|
|||
+ "&" + API.EXAM_API_PING_NUMBER + "=" + num;
|
||||
builder.content(body);
|
||||
|
||||
final MvcResult mvcResult = this.mockMvc
|
||||
.perform(builder)
|
||||
.andExpect(request().asyncStarted())
|
||||
.andDo(MockMvcResultHandlers.log())
|
||||
.andReturn();
|
||||
final ResultActions result = this.mockMvc.perform(asyncDispatch(mvcResult));
|
||||
final ResultActions result = this.mockMvc
|
||||
.perform(builder);
|
||||
return result.andReturn().getResponse();
|
||||
}
|
||||
|
||||
|
@ -284,12 +280,8 @@ public abstract class ExamAPIIntegrationTester {
|
|||
|
||||
final String body = "{ \"type\": \"%s\", \"timestamp\": %s, \"numericValue\": %s, \"text\": \"%s\" }";
|
||||
builder.content(String.format(body, type, timestamp, value, text));
|
||||
final MvcResult mvcResult = this.mockMvc
|
||||
.perform(builder)
|
||||
.andExpect(request().asyncStarted())
|
||||
.andDo(MockMvcResultHandlers.log())
|
||||
.andReturn();
|
||||
final ResultActions result = this.mockMvc.perform(asyncDispatch(mvcResult));
|
||||
final ResultActions result = this.mockMvc
|
||||
.perform(builder);
|
||||
return result.andReturn().getResponse();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue