Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PAGOPA-2170] fix: resolved bug on idempotency key check #117

Merged
merged 6 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions helm/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ apiVersion: v2
name: pagopa-wisp-converter
description: A service that permits to handle nodoInviaRPT and nodoInviaCarrelloRPT request from WISP, interfacing them with GPD system
type: application
version: 0.199.0
appVersion: 0.3.3
version: 0.201.0
appVersion: 0.3.3-2-PAGOPA-2170
dependencies:
- name: microservice-chart
version: 3.0.0
Expand Down
4 changes: 2 additions & 2 deletions helm/values-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ microservice-chart:
fullnameOverride: ""
image:
repository: ghcr.io/pagopa/pagopa-wisp-converter
tag: "0.3.3"
tag: "0.3.3-2-PAGOPA-2170"
pullPolicy: Always
livenessProbe:
httpGet:
Expand Down Expand Up @@ -98,7 +98,7 @@ microservice-chart:
RT_SEND_SCHEDULING_TIME_IN_MINUTES: '1'
RT_SEND_AVOID_SCHEDULING_ON_STATES: 'PAA_RT_DUPLICATA'
RPT_TIMER_QUEUE_NAME: "nodo_wisp_rpt_timeout_queue"
RPT_TIMEOUT: '120' # 2 minutes
RPT_TIMEOUT: '60' # 1 minute
RE_TRACING_INTERFACE_IUVGENERATOR_ENABLED: 'true'
RE_TRACING_INTERFACE_PAYMENTPOSITIONANALYSIS_ENABLED: 'true'
RE_TRACING_INTERFACE_DECOUPLERCACHING_ENABLED: 'true'
Expand Down
2 changes: 1 addition & 1 deletion helm/values-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ microservice-chart:
fullnameOverride: ""
image:
repository: ghcr.io/pagopa/pagopa-wisp-converter
tag: "0.3.3"
tag: "0.3.3-2-PAGOPA-2170"
pullPolicy: Always
livenessProbe:
httpGet:
Expand Down
2 changes: 1 addition & 1 deletion helm/values-uat.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ microservice-chart:
fullnameOverride: ""
image:
repository: ghcr.io/pagopa/pagopa-wisp-converter
tag: "0.3.3"
tag: "0.3.3-2-PAGOPA-2170"
pullPolicy: Always
livenessProbe:
httpGet:
Expand Down
2 changes: 1 addition & 1 deletion openapi/openapi.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion openapi/openapi_redirect.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"openapi": "3.0.1",
"info": {
"title": "WISP-Converter-redirect",
"version": "0.3.3"
"version": "0.3.3-2-PAGOPA-2170"
},
"servers": [
{
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<groupId>it.gov.pagopa</groupId>
<artifactId>wisp-converter</artifactId>
<version>0.3.3</version>
<version>0.3.3-2-PAGOPA-2170</version>
<name>pagoPA WISP Converter</name>
<description>A service that permits to handle nodoInviaRPT and nodoInviaCarrelloRPT request from WISP, converting them in NMU payments.</description>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public enum AppErrorCodeMessageEnum {
RECEIPT_KO_NOT_SENT(1403, "KO Receipt not sent", "Error while sending KO receipt. It is not possible to send the receipt due to an error: [{0}].", HttpStatus.BAD_REQUEST, "An error occurred while sending a negative RT (aka a KO receipt). So, no receipt can be sent lately to creditor institution and probably the process must be executed manually. For better understanding the cause, please use the Technical Support's APIs."),
RECEIPT_OK_NOT_SENT(1404, "OK Receipt not sent", "Error while sending OK receipt. It is not possible to send the receipt due to an error: [{0}].", HttpStatus.BAD_REQUEST, "An error occurred while sending a positive RT (aka a OK receipt). So, no receipt can be sent lately to creditor institution and probably the process must be executed manually. For better understanding the cause, please use the Technical Support's APIs."),
RECEIPT_GENERATION_IDEMPOTENCY_LOCKED_BY_ANOTHER_PROCESS(1405, "Receipt generation not processable", "Error while generating receipt. The idempotency key [{0}] related to receipt was already locked by another process.", HttpStatus.UNPROCESSABLE_ENTITY, "An error occurred while generating an RT (aka a receipt). Two or more generation processes are concurrently trying to execute the same operation on the same receipt but only one of them is currently 'authorized' to do so."),
RECEIPT_GENERATION_NOT_PROCESSABLE(1406, "Receipt generation not processable", "Error while generating receipt. The receipt, related to idempotency key [{0}], cannot be reprocessed again.", HttpStatus.UNPROCESSABLE_ENTITY, "An error occurred while generating an RT (aka a receipt). The process of receipt generation cannot be started correctly because it is trying to lock the idempotency key that is already in a locked state. Probably the process is in execution by another thread."),
RECEIPT_GENERATION_NOT_PROCESSABLE(1406, "Receipt generation not processable", "Error while generating receipt. The receipt, related to idempotency key [{0}], cannot be reprocessed again because it is in status [{1}]", HttpStatus.UNPROCESSABLE_ENTITY, "An error occurred while generating an RT (aka a receipt). The process of receipt generation cannot be started correctly because it is trying to lock the idempotency key that is already in a locked state. Probably the process is in execution by another thread."),
RECEIPT_GENERATION_ALREADY_PROCESSED(1407, "Receipt generation already processed", "Error while generating receipt. The receipt, related to idempotency key [{0}], was already processed by another execution.", HttpStatus.UNPROCESSABLE_ENTITY, "An error occurred while generating an RT (aka a receipt). The process of receipt generation cannot be completed correctly because it is trying to unlock the idempotency key that is not in a locked state. Probably the process was already completed."),
RECEIPT_GENERATION_ANOMALY_ON_PROCESSING(1408, "Anomaly on receipt generation", "Error while generating receipt. The receipt, related to idempotency key [{0}], is of type [{1}] but the invoked endpoint require the send of a [{2}] receipt.", HttpStatus.CONFLICT, "An error occurred while generating an RT (aka a receipt). The process of receipt generation cannot be completed correctly because there is a mismatch between the type of the cached receipt and the kind of request made for generate the same receipt. For example, the cached receipt is defined as negative paaInviaRT but the request was made to 'receipt/ok' endpoint. This is an anomaly that should never happens in a correct NMU flow execution but must be traced in case of error."),
RECEIPT_KO_NOT_GENERATED_BUT_MAYBE_RESCHEDULED(1409, "KO Receipt not generated", "Error while generating KO receipt. It is not possible to generate the receipt and it could be scheduled for a next send.", HttpStatus.UNPROCESSABLE_ENTITY, "An error occurred while generating a negative RT (aka a KO receipt). The receipt could be sent lately to creditor institution but for better understanding the cause, please use the Technical Support's APIs."),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package it.gov.pagopa.wispconverter.service;

import com.azure.cosmos.models.PartitionKey;
import it.gov.pagopa.wispconverter.exception.AppErrorCodeMessageEnum;
import it.gov.pagopa.wispconverter.exception.AppException;
import it.gov.pagopa.wispconverter.repository.IdempotencyKeyRepository;
Expand Down Expand Up @@ -31,8 +30,7 @@ public boolean isIdempotencyKeyProcessable(String idempotencyKey, ReceiptTypeEnu
boolean isProcessable = true;

// try to retrieve idempotency key entity from the storage and check if exists
PartitionKey partitionKey = extractPartitionKeyFromIdempotencyKey(idempotencyKey);
Optional<IdempotencyKeyEntity> optIdempotencyKeyEntity = idempotencyKeyRepository.findById(idempotencyKey, partitionKey);
Optional<IdempotencyKeyEntity> optIdempotencyKeyEntity = idempotencyKeyRepository.findById(idempotencyKey);
if (optIdempotencyKeyEntity.isPresent()) {

/*
Expand All @@ -55,8 +53,7 @@ public boolean isCompleted(String idempotencyKey) {
boolean isSucceeded = false;

// try to retrieve idempotency key entity from the storage and check if exists
PartitionKey partitionKey = extractPartitionKeyFromIdempotencyKey(idempotencyKey);
Optional<IdempotencyKeyEntity> optIdempotencyKeyEntity = idempotencyKeyRepository.findById(idempotencyKey, partitionKey);
Optional<IdempotencyKeyEntity> optIdempotencyKeyEntity = idempotencyKeyRepository.findById(idempotencyKey);
if (optIdempotencyKeyEntity.isPresent()) {

// check if the idempotency key is in a success status
Expand All @@ -71,8 +68,7 @@ public void lockIdempotencyKey(String idempotencyKey, ReceiptTypeEnum receiptTyp
IdempotencyKeyEntity idempotencyKeyEntity;

// try to retrieve idempotency key entity from the storage and check if exists
PartitionKey partitionKey = extractPartitionKeyFromIdempotencyKey(idempotencyKey);
Optional<IdempotencyKeyEntity> optIdempotencyKeyEntity = idempotencyKeyRepository.findById(idempotencyKey, partitionKey);
Optional<IdempotencyKeyEntity> optIdempotencyKeyEntity = idempotencyKeyRepository.findById(idempotencyKey);
if (optIdempotencyKeyEntity.isPresent()) {

// check either if a lock exists and is active and if the status is not failed
Expand All @@ -83,7 +79,7 @@ public void lockIdempotencyKey(String idempotencyKey, ReceiptTypeEnum receiptTyp

} else if (!IdempotencyStatusEnum.FAILED.equals(idempotencyKeyEntity.getStatus())) {

throw new AppException(AppErrorCodeMessageEnum.RECEIPT_GENERATION_NOT_PROCESSABLE, idempotencyKey);
throw new AppException(AppErrorCodeMessageEnum.RECEIPT_GENERATION_NOT_PROCESSABLE, idempotencyKey, idempotencyKeyEntity.getStatus());
}

} else {
Expand All @@ -106,8 +102,7 @@ public void unlockIdempotencyKey(String idempotencyKey, ReceiptTypeEnum receiptT
IdempotencyKeyEntity idempotencyKeyEntity;

// try to retrieve idempotency key entity from the storage and check if exists
PartitionKey partitionKey = extractPartitionKeyFromIdempotencyKey(idempotencyKey);
Optional<IdempotencyKeyEntity> optIdempotencyKeyEntity = idempotencyKeyRepository.findById(idempotencyKey, partitionKey);
Optional<IdempotencyKeyEntity> optIdempotencyKeyEntity = idempotencyKeyRepository.findById(idempotencyKey);
if (optIdempotencyKeyEntity.isPresent()) {

// check if it is not in a locked state
Expand All @@ -132,12 +127,6 @@ public void unlockIdempotencyKey(String idempotencyKey, ReceiptTypeEnum receiptT
idempotencyKeyRepository.save(idempotencyKeyEntity);
}

private PartitionKey extractPartitionKeyFromIdempotencyKey(String idempotencyKey) {

String[] idempotencyKeySections = idempotencyKey.split("_");
return new PartitionKey(idempotencyKeySections[0] + "_" + idempotencyKeySections[1]);
}

private boolean isActiveLockExpired(IdempotencyKeyEntity idempotencyKeyEntity) {

boolean isExpired = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ public void processMessage(ServiceBusReceivedMessageContext context) {

// If receipt was found, it must be sent to creditor institution, so it try this operation
log.debug("Sending message {}, retry: {}", compositedIdForReceipt, rtRequestEntity.getRetry());
resendRTToCreditorInstitution(receiptId, rtRequestEntity, compositedIdForReceipt, idempotencyKey);
boolean isSend = resendRTToCreditorInstitution(receiptId, rtRequestEntity, compositedIdForReceipt, idempotencyKey);

idempotencyStatus = IdempotencyStatusEnum.SUCCESS;
idempotencyStatus = isSend ? IdempotencyStatusEnum.SUCCESS : IdempotencyStatusEnum.FAILED;

} else {

Expand All @@ -138,8 +138,9 @@ public void processMessage(ServiceBusReceivedMessageContext context) {
}
}

private void resendRTToCreditorInstitution(String receiptId, RTRequestEntity receipt, String compositedIdForReceipt, String idempotencyKey) {
private boolean resendRTToCreditorInstitution(String receiptId, RTRequestEntity receipt, String compositedIdForReceipt, String idempotencyKey) {

boolean isSend = false;
try {

log.debug("Sending receipt [{}]", receiptId);
Expand All @@ -164,6 +165,7 @@ private void resendRTToCreditorInstitution(String receiptId, RTRequestEntity rec

// generate a new event in RE for store the successful re-sending of the receipt
generateREForSentRT();
isSend = true;

} catch (AppException e) {

Expand All @@ -177,6 +179,7 @@ private void resendRTToCreditorInstitution(String receiptId, RTRequestEntity rec

throw new AppException(AppErrorCodeMessageEnum.PARSING_INVALID_ZIPPED_PAYLOAD);
}
return isSend;
}

private List<Pair<String, String>> extractHeaders(List<String> headers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ void sendToPa_locked(String receiptType, String rawIsCompleted) {

IdempotencyKeyRepository idempotencyKeyRepository = mock(IdempotencyKeyRepository.class);
IdempotencyService idempotencyService = new IdempotencyService(idempotencyKeyRepository);
when(idempotencyKeyRepository.findById(any(), any())).thenReturn(Optional.of(IdempotencyKeyEntity.builder()
when(idempotencyKeyRepository.findById(any())).thenReturn(Optional.of(IdempotencyKeyEntity.builder()
.status(isCompleted ? IdempotencyStatusEnum.SUCCESS : IdempotencyStatusEnum.LOCKED)
.receiptType("OK".equalsIgnoreCase(receiptType) ? ReceiptTypeEnum.OK : ReceiptTypeEnum.KO)
.lockedAt(Instant.now().minus(1, ChronoUnit.MINUTES))
Expand Down
Loading