Skip to content

Commit

Permalink
add mergedOptions + refactor (#22)
Browse files Browse the repository at this point in the history
* add mergedOptions + refactor

* fine-tuning ExponentialBackOffPollingService

* fix after review
  • Loading branch information
karle0wne authored Oct 22, 2024
1 parent b934fe2 commit 2329359
Show file tree
Hide file tree
Showing 21 changed files with 264 additions and 135 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
package dev.vality.disputes.api.service;

import dev.vality.damsel.domain.Currency;
import dev.vality.damsel.domain.Cash;
import dev.vality.damsel.domain.CurrencyRef;
import dev.vality.damsel.domain.TransactionInfo;
import dev.vality.damsel.payment_processing.InvoicePayment;
import dev.vality.disputes.api.model.PaymentParams;
import dev.vality.disputes.schedule.service.ProviderDataService;
import dev.vality.disputes.security.AccessData;
import dev.vality.disputes.service.external.impl.dominant.DominantAsyncService;
import dev.vality.disputes.service.external.impl.partymgnt.PartyManagementAsyncService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
@RequiredArgsConstructor
public class PaymentParamsBuilder {

private final DominantAsyncService dominantAsyncService;
private final ProviderDataService providerDataService;
private final PartyManagementAsyncService partyManagementAsyncService;

@SneakyThrows
Expand All @@ -29,28 +29,20 @@ public PaymentParams buildGeneralPaymentContext(AccessData accessData) {
log.debug("Start building PaymentParams id={}", invoice.getId());
var payment = accessData.getPayment();
// http 500
var terminal = dominantAsyncService.getTerminal(payment.getRoute().getTerminal());
var currency = Optional.of(payment)
.filter(p -> p.getPayment().isSetCost())
.map(p -> p.getPayment().getCost())
// http 500
.map(cost -> dominantAsyncService.getCurrency(cost.getCurrency()));
var currency = providerDataService.getCurrency(getCurrencyRef(payment));
var shop = partyManagementAsyncService.getShop(invoice.getOwnerId(), invoice.getShopId());
var paymentParams = PaymentParams.builder()
.invoiceId(invoice.getId())
.paymentId(payment.getPayment().getId())
.terminalId(payment.getRoute().getTerminal().getId())
.providerId(payment.getRoute().getProvider().getId())
.providerTrxId(getProviderTrxId(payment))
.currencyName(getCurrency(currency)
.map(Currency::getName).orElse(null))
.currencySymbolicCode(getCurrency(currency)
.map(Currency::getSymbolicCode).orElse(null))
.currencyNumericCode(getCurrency(currency)
.map(Currency::getNumericCode).map(Short::intValue).orElse(null))
.currencyExponent(getCurrency(currency)
.map(Currency::getExponent).map(Short::intValue).orElse(null))
.options(terminal.get().getOptions())
.currencyName(currency.getName())
.currencySymbolicCode(currency.getSymbolicCode())
.currencyNumericCode((int) currency.getNumericCode())
.currencyExponent((int) currency.getExponent())
// http 500
.options(providerDataService.getProviderData(payment).getOptions())
.shopId(invoice.getShopId())
.shopDetailsName(shop.get().getDetails().getName())
.invoiceAmount(payment.getPayment().getCost().getAmount())
Expand All @@ -59,14 +51,12 @@ public PaymentParams buildGeneralPaymentContext(AccessData accessData) {
return paymentParams;
}

private Optional<Currency> getCurrency(Optional<CompletableFuture<Currency>> currency) {
return currency.map(currencyCompletableFuture -> {
try {
return currencyCompletableFuture.get();
} catch (Throwable e) {
throw new RuntimeException(e);
}
});
private CurrencyRef getCurrencyRef(InvoicePayment payment) {
return Optional.of(payment)
.filter(p -> p.getPayment().isSetCost())
.map(p -> p.getPayment().getCost())
.map(Cash::getCurrency)
.orElse(null);
}

private String getProviderTrxId(InvoicePayment payment) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package dev.vality.disputes.polling;

import dev.vality.adapter.flow.lib.model.PollingInfo;
import dev.vality.adapter.flow.lib.utils.backoff.ExponentialBackOff;

import java.time.Instant;
import java.util.Map;

import static dev.vality.adapter.flow.lib.utils.backoff.ExponentialBackOff.*;

public class ExponentialBackOffPollingService {

public int prepareNextPollingInterval(PollingInfo pollingInfo, Map<String, String> options) {
return exponentialBackOff(pollingInfo, options)
.start()
.nextBackOff()
.intValue();
}

private ExponentialBackOff exponentialBackOff(PollingInfo pollingInfo, Map<String, String> options) {
final var currentLocalTime = Instant.now().toEpochMilli();
var startTime = pollingInfo.getStartDateTimePolling() != null
? pollingInfo.getStartDateTimePolling().toEpochMilli()
: currentLocalTime;
var exponential = TimeOptionsExtractors.extractExponent(options, DEFAULT_MUTIPLIER);
var defaultInitialExponential =
TimeOptionsExtractors.extractDefaultInitialExponential(options, DEFAULT_INITIAL_INTERVAL_SEC);
var maxTimeBackOff = TimeOptionsExtractors.extractMaxTimeBackOff(options, DEFAULT_MAX_INTERVAL_SEC);
return new ExponentialBackOff(
startTime,
currentLocalTime,
exponential,
defaultInitialExponential,
maxTimeBackOff);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package dev.vality.disputes.polling;

import dev.vality.adapter.flow.lib.model.PollingInfo;
import dev.vality.adapter.flow.lib.service.ExponentialBackOffPollingService;
import dev.vality.damsel.domain.Terminal;
import dev.vality.damsel.domain.TerminalRef;
import dev.vality.disputes.domain.tables.pojos.Dispute;
import dev.vality.disputes.service.external.DominantService;
import org.springframework.stereotype.Service;

import java.time.Instant;
Expand All @@ -17,10 +13,8 @@
public class ExponentialBackOffPollingServiceWrapper {

private final ExponentialBackOffPollingService exponentialBackOffPollingService;
private final DominantService dominantService;

public ExponentialBackOffPollingServiceWrapper(DominantService dominantService) {
this.dominantService = dominantService;
public ExponentialBackOffPollingServiceWrapper() {
this.exponentialBackOffPollingService = new ExponentialBackOffPollingService();
}

Expand All @@ -29,20 +23,15 @@ public LocalDateTime prepareNextPollingInterval(PollingInfo pollingInfo, Map<Str
return getLocalDateTime(pollingInfo.getStartDateTimePolling().plusSeconds(seconds));
}

public LocalDateTime prepareNextPollingInterval(Dispute dispute) {
public LocalDateTime prepareNextPollingInterval(Dispute dispute, Map<String, String> options) {
var pollingInfo = new PollingInfo();
var startDateTimePolling = dispute.getCreatedAt().toInstant(ZoneOffset.UTC);
pollingInfo.setStartDateTimePolling(startDateTimePolling);
pollingInfo.setMaxDateTimePolling(dispute.getPollingBefore().toInstant(ZoneOffset.UTC));
var terminal = getTerminal(dispute.getTerminalId());
var seconds = exponentialBackOffPollingService.prepareNextPollingInterval(pollingInfo, terminal.getOptions());
var seconds = exponentialBackOffPollingService.prepareNextPollingInterval(pollingInfo, options);
return getLocalDateTime(dispute.getNextCheckAfter().toInstant(ZoneOffset.UTC).plusSeconds(seconds));
}

private Terminal getTerminal(Integer terminalId) {
return dominantService.getTerminal(new TerminalRef(terminalId));
}

private LocalDateTime getLocalDateTime(Instant instant) {
return LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package dev.vality.disputes.polling;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.util.Map;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TimeOptionsExtractors {

public static final String TIMER_EXPONENTIAL = "exponential";
public static final String MAX_TIME_BACKOFF_SEC = "max_time_backoff_sec";
public static final String DEFAULT_INITIAL_EXPONENTIAL_SEC = "default_initial_exponential_sec";
public static final String DISPUTE_TIMER_EXPONENTIAL = "dispute_exponential";
public static final String DISPUTE_MAX_TIME_BACKOFF_SEC = "dispute_max_time_backoff_sec";
public static final String DISPUTE_DEFAULT_INITIAL_EXPONENTIAL_SEC = "dispute_default_initial_exponential_sec";

public static Integer extractExponent(Map<String, String> options, int maxTimePolling) {
return Integer.parseInt(options.getOrDefault(
DISPUTE_TIMER_EXPONENTIAL,
options.getOrDefault(TIMER_EXPONENTIAL, String.valueOf(maxTimePolling))));
}

public static Integer extractMaxTimeBackOff(Map<String, String> options, int maxTimeBackOff) {
return Integer.parseInt(options.getOrDefault(
DISPUTE_MAX_TIME_BACKOFF_SEC,
options.getOrDefault(MAX_TIME_BACKOFF_SEC, String.valueOf(maxTimeBackOff))));
}

public static Integer extractDefaultInitialExponential(Map<String, String> options, int defaultInitialExponential) {
return Integer.parseInt(
options.getOrDefault(DISPUTE_DEFAULT_INITIAL_EXPONENTIAL_SEC,
options.getOrDefault(DEFAULT_INITIAL_EXPONENTIAL_SEC, String.valueOf(
defaultInitialExponential))));
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package dev.vality.disputes.schedule.client;

import dev.vality.damsel.domain.ProviderRef;
import dev.vality.damsel.domain.ProxyDefinition;
import dev.vality.damsel.domain.Terminal;
import dev.vality.damsel.domain.TerminalRef;
import dev.vality.disputes.domain.tables.pojos.Dispute;
import dev.vality.disputes.domain.tables.pojos.ProviderDispute;
import dev.vality.disputes.provider.Attachment;
import dev.vality.disputes.provider.DisputeCreatedResult;
import dev.vality.disputes.provider.DisputeStatusResult;
import dev.vality.disputes.schedule.converter.DisputeContextConverter;
import dev.vality.disputes.schedule.converter.DisputeParamsConverter;
import dev.vality.disputes.schedule.model.ProviderData;
import dev.vality.disputes.schedule.service.ProviderIfaceBuilder;
import dev.vality.disputes.service.external.DominantService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -27,46 +23,32 @@
public class RemoteClient {

private final ProviderIfaceBuilder providerIfaceBuilder;
private final DominantService dominantService;
private final DisputeContextConverter disputeContextConverter;
private final DisputeParamsConverter disputeParamsConverter;

@SneakyThrows
public DisputeCreatedResult createDispute(Dispute dispute, List<Attachment> attachments) {
public DisputeCreatedResult createDispute(Dispute dispute, List<Attachment> attachments, ProviderData providerData) {
log.debug("Trying to call dominant for RemoteClient {}", dispute.getId());
var terminal = getTerminal(dispute.getTerminalId());
var proxy = getProxy(dispute.getProviderId());
log.debug("Trying to build disputeParams {}", dispute.getId());
var disputeParams = disputeParamsConverter.convert(dispute, attachments, terminal.getOptions());
var disputeParams = disputeParamsConverter.convert(dispute, attachments, providerData.getOptions());
log.debug("Trying to call ProviderIfaceBuilder {}", dispute.getId());
var remoteClient = providerIfaceBuilder.buildTHSpawnClient(terminal.getOptions(), proxy.getUrl());
var remoteClient = providerIfaceBuilder.buildTHSpawnClient(providerData);
log.debug("Trying to routed remote provider's createDispute() call {}", dispute.getId());
var result = remoteClient.createDispute(disputeParams);
log.info("Routed remote provider's createDispute() has been called {} {}", dispute.getId(), result);
return result;
}

@SneakyThrows
public DisputeStatusResult checkDisputeStatus(Dispute dispute, ProviderDispute providerDispute) {
public DisputeStatusResult checkDisputeStatus(Dispute dispute, ProviderDispute providerDispute, ProviderData providerData) {
log.debug("Trying to call dominant for RemoteClient {}", dispute.getId());
var terminal = getTerminal(dispute.getTerminalId());
var proxy = getProxy(dispute.getProviderId());
log.debug("Trying to build disputeContext {}", dispute.getId());
var disputeContext = disputeContextConverter.convert(dispute, providerDispute, terminal.getOptions());
var disputeContext = disputeContextConverter.convert(dispute, providerDispute, providerData.getOptions());
log.debug("Trying to call ProviderIfaceBuilder {}", dispute.getId());
var remoteClient = providerIfaceBuilder.buildTHSpawnClient(terminal.getOptions(), proxy.getUrl());
var remoteClient = providerIfaceBuilder.buildTHSpawnClient(providerData);
log.debug("Trying to routed remote provider's checkDisputeStatus() call {}", dispute.getId());
var result = remoteClient.checkDisputeStatus(disputeContext);
log.info("Routed remote provider's checkDisputeStatus() has been called {} {}", dispute.getId(), result);
return result;
}

private ProxyDefinition getProxy(Integer providerId) {
var provider = dominantService.getProvider(new ProviderRef(providerId));
return dominantService.getProxy(provider.getProxy().getRef());
}

private Terminal getTerminal(Integer terminalId) {
return dominantService.getTerminal(new TerminalRef(terminalId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
Expand All @@ -22,11 +24,11 @@ public class DisputeStatusResultHandler {
private final ExponentialBackOffPollingServiceWrapper exponentialBackOffPollingService;

@Transactional(propagation = Propagation.REQUIRED)
public void handleStatusPending(Dispute dispute, DisputeStatusResult result) {
public void handleStatusPending(Dispute dispute, DisputeStatusResult result, Map<String, String> options) {
// дергаем update() чтоб обновить время вызова next_check_after,
// чтобы шедулатор далее доставал пачку самых древних диспутов и смещал
// и этим вызовом мы финализируем состояние диспута, что он был обновлен недавно
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute);
var nextCheckAfter = exponentialBackOffPollingService.prepareNextPollingInterval(dispute, options);
log.info("Trying to set pending Dispute status {}, {}", dispute, result);
disputeDao.update(dispute.getId(), DisputeStatus.pending, nextCheckAfter);
log.debug("Dispute status has been set to pending {}", dispute.getId());
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/dev/vality/disputes/schedule/model/ProviderData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.vality.disputes.schedule.model;

import lombok.Builder;
import lombok.Data;

import java.util.Map;

@Data
@Builder
public class ProviderData {

private Map<String, String> options;
private String defaultProviderUrl;

}
Loading

0 comments on commit 2329359

Please sign in to comment.