diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehavior.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehavior.java index 2e9c5083c..d367f0e88 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehavior.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/behavior/tasks/OperationServiceBehavior.java @@ -763,11 +763,10 @@ public OperationDetailResponse operationDetail(OperationDetailRequest request) t }); final String userId = request.getUserId(); - final OperationEntity operationEntity = expireOperation( - claimOperation(operation, userId, currentTimestamp), - currentTimestamp - ); + final OperationEntity operationEntity = + claimOperation(operation, userId, currentTimestamp); final OperationDetailResponse operationDetailResponse = convertFromEntityAndFillOtp(operationEntity); + markOperationExpired(operationDetailResponse, currentTimestamp); extendAndSetOperationDetailData(operationDetailResponse); return operationDetailResponse; } catch (GenericServiceException ex) { @@ -1013,6 +1012,17 @@ private OperationEntity expireOperation(OperationEntity operationEntity, Date cu return operationEntity; } + private void markOperationExpired(OperationDetailResponse operation, Date currentTimestamp) throws GenericServiceException { + // Operation is still pending and timestamp is after the expiration. + if (OperationStatus.PENDING.equals(operation.getStatus()) + && operation.getTimestampExpires().before(currentTimestamp)) { + // Operation status is persisted only using background service to avoid database deadlocks, + // because two concurrent UPDATE queries can be executed at the same time. + // The status in the database may be updated few seconds later for this reason. + operation.setStatus(OperationStatus.EXPIRED); + } + } + private boolean factorsAcceptable(@NotNull OperationEntity operation, PowerAuthSignatureTypes usedFactor) { final String operationId = operation.getId(); final PowerAuthSignatureTypes[] allowedFactors = operation.getSignatureType();