We are using Spring Boot to develop our servies. We chose to do it in an async way and we are faced with the following problem: We have the following aspect on top of all our async rest resources:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.context.request.async.DeferredResult;
@Aspect
@Component
public class TerminatedUsersAspect {
private static final Logger LOGGER = LoggerFactory.getLogger("[TERMINATED_USERS]");
public static final ThreadLocal<String> ID_LOCAL = new ThreadLocal<>();
@Autowired
private UserRepository userRepo;
@Autowired
private UserService userService;
@Autowired
private ExecutorService executorService;
@SuppressWarnings("unchecked")
@Around("within(com.test..*) && @annotation(authorization)")
public Object checkForId(ProceedingJoinPoint joinPoint, Authorization authorization) throws Throwable {
final MethodInvocationProceedingJoinPoint mJoinPoint = (MethodInvocationProceedingJoinPoint) joinPoint;
final MethodSignature signature = (MethodSignature) mJoinPoint.getSignature();
final DeferredResult<Object> ret = new DeferredResult<>(60000L);
final String id = ID_LOCAL.get();
if (signature.getReturnType().isAssignableFrom(DeferredResult.class) && (id != null)) {
userRepo.getAccountStatus(id).thenAcceptAsync(status -> {
boolean accountValid = userService.isAccountValid(status, true);
if (!accountValid) {
LOGGER.debug("AccountId: {} is not valid. Rejecting with 403", id);
ret.setErrorResult(new ResponseEntity<String>("Invalid account.", HttpStatus.FORBIDDEN));
return;
}
try {
final DeferredResult<Object> funcRet = (DeferredResult<Object>) joinPoint.proceed();
funcRet.setResultHandler(r -> {
ret.setResult(r);
});
funcRet.onTimeout(() -> {
ret.setResult(new AsyncRequestTimeoutException());
});
} catch (Throwable e) {
ret.setErrorResult(ret);
}
}, executorService).exceptionally(ex -> {
ret.setErrorResult(ex);
return null;
});
return ret;
}
return joinPoint.proceed();
}
}
Our embedded server in the application is undertow. The problem arises in time. It seems that after almost one day because of this aspect the CPUs evetually end up spiking 100% red. I debugged the code and seems to be fine from my point of view, but maybe I am missing something ? Any ideas would be welcomed. Thanks, C.