Skip to content

Commit

Permalink
[PAGOPA-2370] fix: Add retry delete session-id (#177)
Browse files Browse the repository at this point in the history
Co-authored-by: pagopa-github-bot <[email protected]>
  • Loading branch information
cap-ang and pagopa-github-bot authored Nov 13, 2024
1 parent 2e4cd25 commit dd605c6
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package it.gov.pagopa.wispconverter.config.client;

import it.gov.pagopa.wispconverter.custom.DecouplerApiClient;
import it.gov.pagopa.wispconverter.service.ReService;
import it.gov.pagopa.wispconverter.util.client.RequestResponseLoggingProperties;
import it.gov.pagopa.wispconverter.util.client.decouplercaching.DecouplerCachingClientLoggingInterceptor;
Expand Down Expand Up @@ -70,6 +71,30 @@ public it.gov.pagopa.gen.wispconverter.client.decouplercaching.invoker.ApiClient
return client;
}

@Bean
public it.gov.pagopa.gen.wispconverter.client.decouplercaching.invoker.ApiClient decouplerCachingClientWithRetry() {
RequestResponseLoggingProperties clientLoggingProperties = decouplerCachingClientLoggingProperties();

DecouplerCachingClientLoggingInterceptor clientLogging = new DecouplerCachingClientLoggingInterceptor(clientLoggingProperties, reService, isTracingOfClientOnREEnabled);

RestTemplate restTemplate = restTemplate();

List<ClientHttpRequestInterceptor> currentInterceptors = restTemplate.getInterceptors();
currentInterceptors.add(clientLogging);
restTemplate.setInterceptors(currentInterceptors);

restTemplate.setErrorHandler(new DecouplerCachingClientResponseErrorHandler());

DecouplerApiClient client = new DecouplerApiClient(restTemplate);

client.setBasePath(basePath);
client.setApiKey(apiKey);
client.setMaxAttemptsForRetry(3);
client.setWaitTimeMillis(50);

return client;
}

private RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// This allows us to read the response more than once - Necessary for debugging.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package it.gov.pagopa.wispconverter.custom;

import it.gov.pagopa.wispconverter.exception.AppException;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.*;

import java.util.List;
import java.util.Map;

public class DecouplerApiClient extends it.gov.pagopa.gen.wispconverter.client.decouplercaching.invoker.ApiClient {

public DecouplerApiClient(RestTemplate restTemplate) {
super(restTemplate);
}

@Override
public <T> ResponseEntity<T> invokeAPI(String path,
HttpMethod method,
Map<String, Object> pathParams,
MultiValueMap<String, String> queryParams,
Object body,
HttpHeaders headerParams,
MultiValueMap<String, String> cookieParams,
MultiValueMap<String, Object> formParams,
List<MediaType> accept,
MediaType contentType,
String[] authNames,
ParameterizedTypeReference<T> returnType)
throws RestClientException {

int attempts = 0;
ResponseEntity<T> response = null;
while (attempts < super.getMaxAttemptsForRetry()) {
try {
response = super.invokeAPI(path, method, pathParams, queryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames, returnType);
break;
} catch (AppException ex) {
attempts = handleAppException(ex, attempts);
} catch (ResourceAccessException ex) {
attempts = handleRetry(ex, attempts);
}
}
return response;
}

private int handleAppException(AppException ex, int attempts) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException runtimeException) {
if (cause instanceof HttpServerErrorException || ((HttpClientErrorException) cause).getStatusCode().equals(HttpStatus.TOO_MANY_REQUESTS)) {
attempts = handleRetry(runtimeException, attempts);
}
} else {
throw ex;
}
return attempts;
}


private int handleRetry(RuntimeException ex, int attempts) {
attempts++;
if (attempts < super.getMaxAttemptsForRetry()) {
try {
Thread.sleep(super.getWaitTimeMillis());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} else {
throw ex;
}
return attempts;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import it.gov.pagopa.wispconverter.repository.model.enumz.ReceiptTypeEnum;
import it.gov.pagopa.wispconverter.service.mapper.RTMapper;
import it.gov.pagopa.wispconverter.service.model.CachedKeysMapping;
import it.gov.pagopa.wispconverter.service.model.PaymentSubjectDTO;
import it.gov.pagopa.wispconverter.service.model.ReceiptDto;
import it.gov.pagopa.wispconverter.service.model.re.ReEventDto;
import it.gov.pagopa.wispconverter.service.model.session.CommonFieldsDTO;
Expand All @@ -39,6 +38,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
Expand All @@ -55,6 +55,7 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

import static it.gov.pagopa.wispconverter.util.Constants.PAA_INVIA_RT;

Expand Down Expand Up @@ -91,6 +92,9 @@ public class ReceiptService {

private final it.gov.pagopa.gen.wispconverter.client.decouplercaching.invoker.ApiClient decouplerCachingClient;

@Autowired
private final it.gov.pagopa.gen.wispconverter.client.decouplercaching.invoker.ApiClient decouplerCachingClientWithRetry;

private final ObjectMapper mapper;

@Value("${wisp-converter.station-in-gpd.partial-path}")
Expand Down Expand Up @@ -176,12 +180,9 @@ public void sendKoPaaInviaRtToCreditorInstitution(String payload) {
*/
public void sendKoPaaInviaRtToCreditorInstitution(List<ReceiptDto> receipts) {
try {

it.gov.pagopa.gen.wispconverter.client.decouplercaching.api.DefaultApi apiInstance = new it.gov.pagopa.gen.wispconverter.client.decouplercaching.api.DefaultApi(decouplerCachingClient);
it.gov.pagopa.gen.wispconverter.client.decouplercaching.model.SessionIdDto sessionIdDto = new it.gov.pagopa.gen.wispconverter.client.decouplercaching.model.SessionIdDto();

// map the received payload as a list of receipts that will be lately evaluated
gov.telematici.pagamenti.ws.papernodo.ObjectFactory objectFactory = new gov.telematici.pagamenti.ws.papernodo.ObjectFactory();
it.gov.pagopa.gen.wispconverter.client.decouplercaching.model.SessionIdDto sessionIdDto = new it.gov.pagopa.gen.wispconverter.client.decouplercaching.model.SessionIdDto();

// retrieve configuration data from cache
ConfigDataV1Dto configData = configCacheService.getConfigData();
Expand All @@ -192,9 +193,8 @@ public void sendKoPaaInviaRtToCreditorInstitution(List<ReceiptDto> receipts) {
for (ReceiptDto receipt : receipts) {
// workaround to reuse endpoint service. in this case sessionId = sessionId_fiscalCode_noticeNumber
sessionIdDto.setSessionId(String.format("%s_%s_%s", receipt.getSessionId(), receipt.getFiscalCode(), receipt.getNoticeNumber()));

// necessary to block activatePaymentNoticeV2
apiInstance.deleteSessionId(sessionIdDto, MDC.get(Constants.MDC_REQUEST_ID));
// delete 2_wisp_timer_hang_{wisp_delete_sessionId} from cache via APIM call
this.deleteHangTimerCacheKey(sessionIdDto);

MDCUtil.setReceiptTimerInfoInMDC(receipt.getFiscalCode(), receipt.getNoticeNumber(), null);

Expand Down Expand Up @@ -726,16 +726,11 @@ private void generateRE(InternalStepStatus status, String iuv, String noticeNumb
}

public void sendRTKoFromSessionId(String sessionId, InternalStepStatus internalStepStatus) {

log.debug("Processing session id: {}", sessionId);

// deactivate the sessionId inside the cache
it.gov.pagopa.gen.wispconverter.client.decouplercaching.api.DefaultApi apiInstance = new it.gov.pagopa.gen.wispconverter.client.decouplercaching.api.DefaultApi(decouplerCachingClient);
log.debug("[sendRTKoFromSessionId] Processing session id: {}", sessionId);
it.gov.pagopa.gen.wispconverter.client.decouplercaching.model.SessionIdDto sessionIdDto = new it.gov.pagopa.gen.wispconverter.client.decouplercaching.model.SessionIdDto();
sessionIdDto.setSessionId(sessionId);

// necessary only if rptTimer is triggered, otherwise it has already been removed
apiInstance.deleteSessionId(sessionIdDto, MDC.get(Constants.MDC_REQUEST_ID));
// delete 2_wisp_timer_hang_{wisp_delete_sessionId} from cache via APIM call
this.deleteHangTimerCacheKey(sessionIdDto);

// log event
MDC.put(Constants.MDC_SESSION_ID, sessionId);
Expand Down Expand Up @@ -829,6 +824,24 @@ public void sendRTKoFromSessionId(String sessionId, InternalStepStatus internalS
MDC.clear();
}

/**
* sessionIdDto could contain sessionId or sessionId_fiscalCode_noticeNumber
* @param sessionIdDto
*/
private void deleteHangTimerCacheKey(it.gov.pagopa.gen.wispconverter.client.decouplercaching.model.SessionIdDto sessionIdDto) {
// deactivate the sessionId inside the cache
it.gov.pagopa.gen.wispconverter.client.decouplercaching.api.DefaultApi apiInstance = new it.gov.pagopa.gen.wispconverter.client.decouplercaching.api.DefaultApi(decouplerCachingClientWithRetry);

CompletableFuture.runAsync(() -> {
log.info("[{}][cache-key={}] delete-hang-timer-cache-key", sessionIdDto.getSessionId(), Instant.now().toString());
// necessary only if rptTimer is triggered, otherwise it has already been removed
apiInstance.deleteSessionId(sessionIdDto, MDC.get(Constants.MDC_REQUEST_ID));
}).exceptionally(throwable -> {
log.error("[cache-key={}] Exception while delete-hang-timer-cache-key: {}", sessionIdDto.getSessionId(), throwable.getMessage());
return null;
});
}

private RTRequestEntity generateRTRequestEntity(SessionDataDTO sessionData, URI uri, InetSocketAddress proxyAddress, List<Pair<String, String>> headers, String payload,
StationDto station, RPTContentDTO rpt, String idempotencyKey, ReceiptTypeEnum receiptType) throws IOException {
List<String> formattedHeaders = new LinkedList<>();
Expand Down

0 comments on commit dd605c6

Please sign in to comment.