SEBSERV-250 made disableConnection call asynchronous when there are more

then one connection involved. This result in immediately response on UI
side.
This commit is contained in:
anhefti 2022-01-10 09:19:43 +01:00
parent 863511dbc7
commit d7c71ea930
3 changed files with 47 additions and 8 deletions

View file

@ -9,7 +9,9 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.session;
import java.security.Principal;
import java.util.Collection;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
import ch.ethz.seb.sebserver.gbl.util.Result;
@ -124,6 +126,17 @@ public interface SEBClientConnectionService {
* @return A Result refer to the closed ClientConnection instance, or refer to an error if happened */
Result<ClientConnection> disableConnection(String connectionToken, Long institutionId);
/** This is used to disable multiple undefined or requested ClientConnection attempt from the SEB Server side
* <p>
* This will save the existing ClientConnections that are in UNDEFINED or REQUESTED state, in new DISABLED state and
* flush caches.
*
* @param connectionTokens String array of connection tokens of connections to disable
* @param institutionId institution identifier
* @return A Result refer to a list of EntityKey of the closed ClientConnection instances, or refer to an error if
* happened */
Result<Collection<EntityKey>> disableConnections(final String[] connectionTokens, final Long institutionId);
/** Used to check current cached ping times of all running connections and
* if a ping time is overflowing, creating a ping overflow event or if an
* overflowed ping is back to normal, a ping back to normal event. */

View file

@ -10,10 +10,13 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
import java.math.BigDecimal;
import java.security.Principal;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
@ -24,6 +27,7 @@ import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType;
@ -571,6 +575,20 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
});
}
@Override
public Result<Collection<EntityKey>> disableConnections(final String[] connectionTokens, final Long institutionId) {
return Result.tryCatch(() -> {
return Stream.of(connectionTokens)
.map(token -> disableConnection(token, institutionId)
.onError(error -> log.error("Failed to disable SEB client connection: {}", token))
.getOr(null))
.filter(clientConnection -> clientConnection != null)
.map(clientConnection -> clientConnection.getEntityKey())
.collect(Collectors.toList());
});
}
@Override
public void updatePingEvents() {
try {

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Objects;
import java.util.concurrent.Executor;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
@ -18,6 +19,7 @@ import javax.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.WebDataBinder;
@ -34,6 +36,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
@ -67,13 +70,15 @@ public class ExamMonitoringController {
private final AuthorizationService authorization;
private final PaginationService paginationService;
private final SEBClientNotificationService sebClientNotificationService;
private final Executor executor;
public ExamMonitoringController(
final SEBClientConnectionService sebClientConnectionService,
final SEBClientInstructionService sebClientInstructionService,
final AuthorizationService authorization,
final PaginationService paginationService,
final SEBClientNotificationService sebClientNotificationService) {
final SEBClientNotificationService sebClientNotificationService,
@Qualifier(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME) final Executor executor) {
this.sebClientConnectionService = sebClientConnectionService;
this.examSessionService = sebClientConnectionService.getExamSessionService();
@ -81,6 +86,7 @@ public class ExamMonitoringController {
this.authorization = authorization;
this.paginationService = paginationService;
this.sebClientNotificationService = sebClientNotificationService;
this.executor = executor;
}
/** This is called by Spring to initialize the WebDataBinder and is used here to
@ -293,14 +299,16 @@ public class ExamMonitoringController {
checkPrivileges(institutionId, examId);
// TODO do this async like registerInstruction
if (connectionToken.contains(Constants.LIST_SEPARATOR)) {
final String[] tokens = StringUtils.split(connectionToken, Constants.LIST_SEPARATOR);
for (int i = 0; i < tokens.length; i++) {
final String token = tokens[i];
this.sebClientConnectionService.disableConnection(token, institutionId)
.onError(error -> log.error("Failed to disable SEB client connection: {}", token));
}
// If we have a bunch of client connections to disable, make it asynchronously and respond to the caller immediately
this.executor.execute(() -> {
final String[] tokens = StringUtils.split(connectionToken, Constants.LIST_SEPARATOR);
this.sebClientConnectionService
.disableConnections(tokens, institutionId)
.onError(error -> log.error(
"Unexpected error while disable connection. See previous logs for more information.",
error));
});
} else {
this.sebClientConnectionService
.disableConnection(connectionToken, institutionId)