Skip to content
Snippets Groups Projects
Commit 24f23a92 authored by Filip Kollár's avatar Filip Kollár
Browse files

added asynchronous execution of transactions

parent 48e75600
No related branches found
No related tags found
1 merge request!39Resolve "Asynchronous transaction processing"
This commit is part of merge request !39. Comments created here will be created in the context of that merge request.
......@@ -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>
......
......@@ -2,6 +2,7 @@ package cz.muni.fi.obs.data.dbo;
public enum TransactionState {
PROCESSING,
SUCCESSFUL,
FAILED;
}
......@@ -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) {
......
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);
}
}
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);
}
}
......@@ -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;
}
......
ALTER TABLE transactions
ALTER COLUMN deposited_amount drop not null;
ALTER TABLE transactions
ALTER COLUMN conversion_rate drop not null;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment