From 24f23a9233be5558a82d17937c2fc72d6fbbf489 Mon Sep 17 00:00:00 2001 From: xkollar3 <xkollar3@fi.muni.cz> Date: Tue, 30 Apr 2024 15:09:10 +0200 Subject: [PATCH] added asynchronous execution of transactions --- transaction-service/pom.xml | 5 +++ .../fi/obs/data/dbo/TransactionState.java | 1 + .../facade/TransactionManagementFacade.java | 5 ++- .../java/cz/muni/fi/obs/jms/JmsConsumer.java | 27 +++++++++++++++ .../java/cz/muni/fi/obs/jms/JmsProducer.java | 25 ++++++++++++++ .../fi/obs/service/TransactionService.java | 33 ++++++++++++------- .../V2__drop_transaction_not_null.sql | 4 +++ 7 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsConsumer.java create mode 100644 transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsProducer.java create mode 100644 transaction-service/src/main/resources/db.migration/V2__drop_transaction_not_null.sql diff --git a/transaction-service/pom.xml b/transaction-service/pom.xml index 80f2de9..9ad106c 100644 --- a/transaction-service/pom.xml +++ b/transaction-service/pom.xml @@ -110,6 +110,11 @@ <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-jms</artifactId> + <version>6.1.6</version> + </dependency> </dependencies> <build> diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/data/dbo/TransactionState.java b/transaction-service/src/main/java/cz/muni/fi/obs/data/dbo/TransactionState.java index e4fab66..815d5f4 100644 --- a/transaction-service/src/main/java/cz/muni/fi/obs/data/dbo/TransactionState.java +++ b/transaction-service/src/main/java/cz/muni/fi/obs/data/dbo/TransactionState.java @@ -2,6 +2,7 @@ package cz.muni.fi.obs.data.dbo; public enum TransactionState { + PROCESSING, SUCCESSFUL, FAILED; } diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/facade/TransactionManagementFacade.java b/transaction-service/src/main/java/cz/muni/fi/obs/facade/TransactionManagementFacade.java index 41696dd..35d0944 100644 --- a/transaction-service/src/main/java/cz/muni/fi/obs/facade/TransactionManagementFacade.java +++ b/transaction-service/src/main/java/cz/muni/fi/obs/facade/TransactionManagementFacade.java @@ -5,6 +5,7 @@ import cz.muni.fi.obs.api.TransactionCreateDto; import cz.muni.fi.obs.data.dbo.AccountDbo; import cz.muni.fi.obs.data.dbo.TransactionDbo; import cz.muni.fi.obs.exceptions.ResourceNotFoundException; +import cz.muni.fi.obs.jms.JmsProducer; import cz.muni.fi.obs.service.AccountService; import cz.muni.fi.obs.service.TransactionService; import lombok.extern.slf4j.Slf4j; @@ -22,11 +23,13 @@ public class TransactionManagementFacade { private final TransactionService transactionService; private final AccountService accountService; + private final JmsProducer jmsProducer; @Autowired - public TransactionManagementFacade(TransactionService transactionService, AccountService accountService) { + public TransactionManagementFacade(TransactionService transactionService, AccountService accountService, JmsProducer jmsProducer) { this.transactionService = transactionService; this.accountService = accountService; + this.jmsProducer = jmsProducer; } public Optional<TransactionDbo> getTransactionById(String id) { diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsConsumer.java b/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsConsumer.java new file mode 100644 index 0000000..6061cf1 --- /dev/null +++ b/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsConsumer.java @@ -0,0 +1,27 @@ +package cz.muni.fi.obs.jms; + +import cz.muni.fi.obs.service.TransactionService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jms.annotation.JmsListener; +import org.springframework.stereotype.Component; + +import static cz.muni.fi.obs.jms.JmsProducer.TRANSACTION_QUEUE_NAME; + +@Component +@Slf4j +public class JmsConsumer { + + private final TransactionService transactionService; + + @Autowired + public JmsConsumer(TransactionService transactionService) { + this.transactionService = transactionService; + } + + @JmsListener(destination = TRANSACTION_QUEUE_NAME, concurrency = "1-4") + public void listenTransactions(String transactionId) { + log.info("Executing transaction with id: " + transactionId); + transactionService.executeTransaction(transactionId); + } +} diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsProducer.java b/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsProducer.java new file mode 100644 index 0000000..e9106f8 --- /dev/null +++ b/transaction-service/src/main/java/cz/muni/fi/obs/jms/JmsProducer.java @@ -0,0 +1,25 @@ +package cz.muni.fi.obs.jms; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class JmsProducer { + + private final JmsTemplate jmsTemplate; + public final static String TRANSACTION_QUEUE_NAME = "transactions"; + + + @Autowired + public JmsProducer(JmsTemplate jmsTemplate) { + this.jmsTemplate = jmsTemplate; + } + + public void sendMessage(String transactionId) { + log.info("Attempting to send message: " + transactionId); + jmsTemplate.convertAndSend(TRANSACTION_QUEUE_NAME, transactionId); + } +} diff --git a/transaction-service/src/main/java/cz/muni/fi/obs/service/TransactionService.java b/transaction-service/src/main/java/cz/muni/fi/obs/service/TransactionService.java index 8671edb..a8e8781 100644 --- a/transaction-service/src/main/java/cz/muni/fi/obs/service/TransactionService.java +++ b/transaction-service/src/main/java/cz/muni/fi/obs/service/TransactionService.java @@ -22,6 +22,7 @@ import java.util.Optional; import java.util.UUID; import static cz.muni.fi.obs.data.dbo.TransactionState.FAILED; +import static cz.muni.fi.obs.data.dbo.TransactionState.PROCESSING; import static cz.muni.fi.obs.data.dbo.TransactionState.SUCCESSFUL; @Slf4j @@ -71,29 +72,37 @@ public class TransactionService { AccountDbo depositsToAccount = accountRepository.findAccountDboByAccountNumber(transaction.depositsToAccountNumber()) .orElseThrow(() -> new ResourceNotFoundException(AccountDbo.class, transaction.depositsToAccountNumber())); - CurrencyExchangeRequest request = CurrencyExchangeRequest.builder() - .from(transaction.withdrawsFromAccountNumber()) - .to(transaction.depositsToAccountNumber()) - .amount(transaction.withdrawAmount()) - .build(); - - CurrencyExchangeResult exchangeResult = callCurrencyClient(request); - - var transactionDbo = TransactionDbo.builder() + TransactionDbo transactionDbo = TransactionDbo.builder() .id(UUID.randomUUID().toString()) .withdrawsFrom(withdrawsFromAccount) .note(transaction.note()) .depositsTo(depositsToAccount) - .depositAmount(exchangeResult.destAmount()) .withdrawAmount(transaction.withdrawAmount()) .variableSymbol(transaction.variableSymbol()) - .conversionRate(exchangeResult.exchangeRate()) - .transactionState(computeTransactionState(withdrawsFromAccount.getId(), transaction.withdrawAmount())) + .transactionState(PROCESSING) .build(); return repository.save(transactionDbo); } + public void executeTransaction(String transactionId) { + TransactionDbo transaction = repository.findById(transactionId) + .orElseThrow(() -> new ResourceNotFoundException(TransactionDbo.class, transactionId)); + + CurrencyExchangeRequest request = CurrencyExchangeRequest.builder() + .from(transaction.getWithdrawsFrom().getCurrencyCode()) + .to(transaction.getDepositsTo().getCurrencyCode()) + .amount(transaction.getWithdrawAmount()) + .build(); + + CurrencyExchangeResult exchangeResult = callCurrencyClient(request); + + transaction.setConversionRate(exchangeResult.exchangeRate()); + transaction.setDepositAmount(exchangeResult.destAmount()); + transaction.setTransactionState(computeTransactionState(transaction.getWithdrawsFrom().getId(), transaction.getWithdrawAmount())); + repository.save(transaction); + } + private TransactionState computeTransactionState(String id, BigDecimal withdrawAmount) { return calculateAccountBalance(id).compareTo(withdrawAmount) > 0 ? SUCCESSFUL : FAILED; } diff --git a/transaction-service/src/main/resources/db.migration/V2__drop_transaction_not_null.sql b/transaction-service/src/main/resources/db.migration/V2__drop_transaction_not_null.sql new file mode 100644 index 0000000..6074b17 --- /dev/null +++ b/transaction-service/src/main/resources/db.migration/V2__drop_transaction_not_null.sql @@ -0,0 +1,4 @@ +ALTER TABLE transactions + ALTER COLUMN deposited_amount drop not null; +ALTER TABLE transactions + ALTER COLUMN conversion_rate drop not null; -- GitLab