Skip to content
Merged

Dev #156

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
70cf64d
refactor: errorinjection 제거
109an94 Jun 6, 2025
c79d287
Merge branch 'dev' of https://github.com/CleanEngine/cleanengine-be i…
109an94 Jun 6, 2025
220b8f9
config: prometheus, grafana 설정
109an94 Jun 6, 2025
cf35215
test: refresher 코드 수정
109an94 Jun 7, 2025
4856ed7
test: refresher 코드 수정
109an94 Jun 7, 2025
0d6667d
test: 성능테스트 환경 구성
caniro Jun 8, 2025
918b265
feat: 체결량 변경
109an94 Jun 8, 2025
b3f3819
config: bastion host를 통해 배포되도록 변경
caniro Jun 10, 2025
90ac9a7
config: actuator yml 설정
109an94 Jun 10, 2025
9b9672e
fix: 볼륨0 잘못된 주문 문제 해결
109an94 Jun 10, 2025
81199dd
refactor: 주석 등 수정
109an94 Jun 10, 2025
c4f6f7a
Merge branch 'dev' of https://github.com/CleanEngine/cleanengine-be i…
109an94 Jun 11, 2025
f0980de
refactor: metric overhead 개선
109an94 Jun 11, 2025
57ee983
refactor: thread-sleep제거
109an94 Jun 11, 2025
9e19994
Merge pull request #142 from CleanEngine/config/ci-cd
caniro Jun 11, 2025
2ea0862
fix: NPE 문제 해결
109an94 Jun 11, 2025
5d1defd
Merge pull request #143 from CleanEngine/feat/realitybot
109an94 Jun 11, 2025
bd56c24
feat: 체결 확정 수량이 0인 경우, 문제가 되는 주문은 큐에서 제거되도록 개선
caniro Jun 11, 2025
d0ce068
Merge branch 'dev' into feat/trade-core
caniro Jun 11, 2025
3626640
chore: 불필요 클래스 삭제
caniro Jun 11, 2025
b9ce729
feat: 종목을 DB에서 조회하도록 변경(아직 사용되는 단계는 아니지만 선반영)
caniro Jun 11, 2025
6fd5caa
fix: 체결 예외 시 복구 후 다음 쌍을 매칭하도록 로직 수정
caniro Jun 11, 2025
7ab9d57
fix: realitybot 초기 작동 이슈 해결
109an94 Jun 11, 2025
c84999a
test: schedulerconfig 관련 삭제
109an94 Jun 11, 2025
65f80c1
Merge branch 'dev' of https://github.com/CleanEngine/cleanengine-be i…
109an94 Jun 11, 2025
a65d001
config: add gitignore
Junh-b Jun 8, 2025
e4d5773
feat: 체결 단일스레드 처리로 변경
Junh-b Jun 9, 2025
9dc0656
feat: handling concurrency
Junh-b Jun 11, 2025
da06ed3
refactor: OrderService의 참조 Repository 변경
Junh-b Jun 11, 2025
9c4ab86
test: OrderService 동시성 테스트 추가
Junh-b Jun 11, 2025
b3b583c
test: orderservice 동시성 적용버전
Junh-b Jun 11, 2025
2af0560
fix: READ_COMMITTED 및 비관적 락 사용을 통한 동시성 문제 해소
caniro Jun 11, 2025
5a7c2f6
chore: 불필요 테스트 삭제
caniro Jun 11, 2025
44c2e2a
rename: 옥수수 삭제
109an94 Jun 11, 2025
e1b9584
fix: h2환경 실행 시 NPE 해결
109an94 Jun 11, 2025
38d2f8a
add: 주석 삭제
109an94 Jun 11, 2025
748d485
Merge pull request #148 from CleanEngine/feat/realitybot
109an94 Jun 11, 2025
f1ca7a6
add: account, wallet 인덱스 추가
caniro Jun 12, 2025
dadc814
config: 필수 config 재수정
Junh-b Jun 12, 2025
cbe002a
refactor: Account, Wallet 레포지터리 통일
Junh-b Jun 12, 2025
e6af112
Merge branch 'dev' into feat/trade-core
caniro Jun 12, 2025
164c6b1
chore: typo(static method 호출)
caniro Jun 12, 2025
010c106
Merge pull request #150 from CleanEngine/feat/trade-core
caniro Jun 12, 2025
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 .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ jobs:
- name: Connect to cloud server and run Docker commands
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{secrets.BACKEND_HOST}}
host: ${{secrets.CLOUD_HOST}}
username: ${{secrets.CLOUD_USERNAME}}
key: ${{secrets.CLOUD_SECRET_KEY}}
port: ${{secrets.CLOUD_PORT}}
script: |
cd ~
/bin/bash run_springboot.sh
/bin/bash deploy_spring.sh
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ out/

### 로컬 환경변수 ###
local.properties
/logs
/logs
docker-compose.override.yml
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ dependencies {

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8'
implementation 'org.springframework.boot:spring-boot-starter-actuator'

implementation 'io.micrometer:micrometer-registry-prometheus'

implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.google.code.gson:gson:2.13.1'
Expand Down
5 changes: 3 additions & 2 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ services:
volumes:
- ../build/libs/coin-0.0.1-SNAPSHOT.jar:/app/coin-0.0.1-SNAPSHOT.jar
- /etc/localtime:/etc/localtime:ro
- /home/ubuntu/logs/springboot:/app/logs
working_dir: /app
command: ["java", "-jar", "coin-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=dev,mariadb-local"]
command: ["java", "-jar", "coin-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=dev,it,mariadb-local"]
ports:
- "8080:8080"
- "5005:5005"
env_file:
- ./local.properties
environment:
- TZ=Asia/Seoul
- JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
depends_on:
mariadb:
condition: service_healthy
Expand Down
6 changes: 6 additions & 0 deletions docker/mariadb/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ create table account
user_id int not null
);

create or replace index idx_account_user_id
on account (user_id);

create table asset
(
ticker varchar(10) not null
Expand Down Expand Up @@ -91,6 +94,9 @@ create table wallet
ticker varchar(10) not null
);

create or replace index idx_wallet_account_id_ticker
on wallet (account_id, ticker);



INSERT INTO `if`.users (user_id, created_at) VALUES (1, '2025-05-16 09:30:00.000000');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.cleanengine.coin.common.annotation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Aspect
@Component
public class TransactionLoggingAspect {

private static final String TRANSACTION_ID_KEY = "txId";

@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object logTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
String txId = UUID.randomUUID().toString().substring(0, 8);
MDC.put(TRANSACTION_ID_KEY, txId);

try {
return joinPoint.proceed();
} finally {
MDC.remove(TRANSACTION_ID_KEY);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.cleanengine.coin.configuration.bootstrap;

import com.cleanengine.coin.order.domain.Asset;
import com.cleanengine.coin.order.adapter.out.persistentce.wallet.OrderWalletRepository;
import com.cleanengine.coin.order.adapter.out.persistentce.asset.AssetRepository;
import com.cleanengine.coin.order.domain.Asset;
import com.cleanengine.coin.user.domain.Account;
import com.cleanengine.coin.user.domain.User;
import com.cleanengine.coin.user.domain.Wallet;
import com.cleanengine.coin.user.info.infra.AccountRepository;
import com.cleanengine.coin.user.info.infra.UserRepository;
import com.cleanengine.coin.user.info.infra.WalletRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
Expand All @@ -24,7 +24,7 @@
public class DBInitRunner implements CommandLineRunner {
private final AccountRepository accountRepository;
private final UserRepository userRepository;
private final OrderWalletRepository orderWalletRepository;
private final WalletRepository walletRepository;
private final AssetRepository assetRepository;

@Transactional
Expand Down Expand Up @@ -58,7 +58,7 @@ protected void initSellBotData(){
wallet2.setTicker("TRUMP");
wallet2.setAccountId(account.getId());
wallet2.setSize(500_000_000.0);
orderWalletRepository.saveAll(List.of(wallet, wallet2));
walletRepository.saveAll(List.of(wallet, wallet2));
}

@Transactional
Expand All @@ -80,7 +80,7 @@ protected void initBuyBotData() {
wallet2.setTicker("TRUMP");
wallet2.setAccountId(account.getId());
wallet2.setSize(0.0);
orderWalletRepository.saveAll(List.of(wallet, wallet2));
walletRepository.saveAll(List.of(wallet, wallet2));
}

@Transactional
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ public List<AssetInfo> getAllAssetInfos(){
return assetRepository.findAll().stream().map(AssetInfo::from).toList();
}

public List<String> getAllAssetTickers(){
return assetRepository.findAll().stream().map(Asset::getTicker).toList();
}

public boolean isAssetExist(String ticker){
if(assetCacheRepository.isAssetExists(ticker)) return true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import jakarta.validation.Validator;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
Expand All @@ -22,11 +23,11 @@
@Service
@RequiredArgsConstructor
@Validated
public class OrderService {
public class OrderService {
private final List<CreateOrderStrategy<?, ?>> createOrderStrategies;
private final Validator validator;

@Transactional
@Transactional(isolation = Isolation.READ_COMMITTED)
public OrderInfo<?> createOrder(OrderCommand.CreateOrder createOrder){
validateCreateOrder(createOrder);
CreateOrderStrategy<?, ?> createOrderStrategy = createOrderStrategies.stream()
Expand All @@ -35,14 +36,14 @@ public OrderInfo<?> createOrder(OrderCommand.CreateOrder createOrder){
return createOrderStrategy.processCreatingOrder(createOrder);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public OrderInfo<?> createOrderWithBot(String ticker, Boolean isBuyOrder, Double orderSize, Double price){
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
public void createOrderWithBot(String ticker, Boolean isBuyOrder, Double orderSize, Double price){
Integer userId = isBuyOrder? BUY_ORDER_BOT_ID : SELL_ORDER_BOT_ID;

OrderCommand.CreateOrder createOrder = new OrderCommand.CreateOrder(ticker, userId, isBuyOrder,
false, orderSize, price, LocalDateTime.now(), true);

return createOrder(createOrder);
createOrder(createOrder);
}

protected void validateCreateOrder(OrderCommand.CreateOrder createOrder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.cleanengine.coin.order.application.strategy;

import com.cleanengine.coin.common.error.DomainValidationException;
import com.cleanengine.coin.order.adapter.out.persistentce.account.OrderAccountRepository;
import com.cleanengine.coin.order.adapter.out.persistentce.order.command.BuyOrderRepository;
import com.cleanengine.coin.order.adapter.out.persistentce.wallet.OrderWalletRepository;
import com.cleanengine.coin.order.application.AssetService;
import com.cleanengine.coin.order.application.dto.OrderInfo;
import com.cleanengine.coin.order.application.port.out.PublishOrderCreatedPort;
Expand All @@ -12,6 +10,8 @@
import com.cleanengine.coin.order.domain.domainservice.CreateBuyOrderDomainService;
import com.cleanengine.coin.order.domain.domainservice.CreateOrderDomainService;
import com.cleanengine.coin.user.domain.Account;
import com.cleanengine.coin.user.info.infra.AccountRepository;
import com.cleanengine.coin.user.info.infra.WalletRepository;
import org.springframework.stereotype.Component;
import org.springframework.validation.FieldError;

Expand Down Expand Up @@ -57,11 +57,11 @@ protected OrderInfo.BuyOrderInfo extractOrderInfo(Order order) {

public BuyOrderStrategy(PublishOrderCreatedPort publishOrderCreatedPort,
AssetService assetService,
OrderWalletRepository orderWalletRepository,
OrderAccountRepository orderAccountRepository,
WalletRepository walletRepository,
AccountRepository accountRepository,
BuyOrderRepository buyOrderRepository,
CreateBuyOrderDomainService createOrderDomainService) {
super(publishOrderCreatedPort, assetService, orderWalletRepository, orderAccountRepository);
super(publishOrderCreatedPort, assetService, walletRepository, accountRepository);
this.buyOrderRepository = buyOrderRepository;
this.createOrderDomainService = createOrderDomainService;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package com.cleanengine.coin.order.application.strategy;

import com.cleanengine.coin.common.error.DomainValidationException;
import com.cleanengine.coin.order.adapter.out.persistentce.account.OrderAccountRepository;
import com.cleanengine.coin.order.adapter.out.persistentce.wallet.OrderWalletRepository;
import com.cleanengine.coin.order.application.AssetService;
import com.cleanengine.coin.order.application.dto.OrderCommand;
import com.cleanengine.coin.order.application.dto.OrderInfo;
import com.cleanengine.coin.order.application.event.OrderCreated;
import com.cleanengine.coin.order.application.port.out.PublishOrderCreatedPort;
import com.cleanengine.coin.order.domain.Order;
import com.cleanengine.coin.order.domain.domainservice.CreateOrderDomainService;
import com.cleanengine.coin.user.domain.Account;
import com.cleanengine.coin.user.domain.Wallet;
import com.cleanengine.coin.user.info.infra.AccountRepository;
import com.cleanengine.coin.user.info.infra.WalletRepository;
import lombok.AllArgsConstructor;
import org.springframework.validation.FieldError;

Expand All @@ -21,14 +19,13 @@
public abstract class CreateOrderStrategy<T extends Order, S extends OrderInfo<?>> {
protected final PublishOrderCreatedPort publishOrderCreatedPort;
protected final AssetService assetService;
protected final OrderWalletRepository walletRepository;
protected final OrderAccountRepository accountRepository;
protected final WalletRepository walletRepository;
protected final AccountRepository accountRepository;

public S processCreatingOrder(OrderCommand.CreateOrder createOrderCommand){
validateTicker(createOrderCommand.ticker());
T order = createOrder(createOrderCommand);
saveOrder(order);
createWalletIfNeeded(order.getUserId(), order.getTicker());
keepHoldings(order);
publishOrderCreatedPort.publish(new OrderCreated(order));
return extractOrderInfo(order);
Expand All @@ -49,21 +46,12 @@ protected void validateTicker(String ticker){
}

protected T createOrder(OrderCommand.CreateOrder createOrderCommand){
T order = createOrderDomainService().createOrder(

return createOrderDomainService().createOrder(
createOrderCommand.ticker(), createOrderCommand.userId(),
createOrderCommand.isBuyOrder(), createOrderCommand.isMarketOrder(),
createOrderCommand.orderSize(), createOrderCommand.price(),
createOrderCommand.createdAt(), createOrderCommand.isBot());

return order;
}

// TODO 책임이 너무 많은
protected void createWalletIfNeeded(Integer userId, String ticker){
if(walletRepository.findWalletBy(userId, ticker).isEmpty()){
Account account = accountRepository.findByUserId(userId).orElseThrow();
Wallet wallet = Wallet.generateEmptyWallet(ticker, account.getId());
walletRepository.save(wallet);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.cleanengine.coin.order.application.strategy;

import com.cleanengine.coin.common.error.DomainValidationException;
import com.cleanengine.coin.order.adapter.out.persistentce.account.OrderAccountRepository;
import com.cleanengine.coin.order.adapter.out.persistentce.order.command.SellOrderRepository;
import com.cleanengine.coin.order.adapter.out.persistentce.wallet.OrderWalletRepository;
import com.cleanengine.coin.order.application.AssetService;
import com.cleanengine.coin.order.application.dto.OrderInfo;
import com.cleanengine.coin.order.application.port.out.PublishOrderCreatedPort;
Expand All @@ -12,6 +10,8 @@
import com.cleanengine.coin.order.domain.domainservice.CreateOrderDomainService;
import com.cleanengine.coin.order.domain.domainservice.CreateSellOrderDomainService;
import com.cleanengine.coin.user.domain.Wallet;
import com.cleanengine.coin.user.info.infra.AccountRepository;
import com.cleanengine.coin.user.info.infra.WalletRepository;
import org.springframework.stereotype.Component;
import org.springframework.validation.FieldError;

Expand Down Expand Up @@ -39,7 +39,7 @@ protected void keepHoldings(SellOrder order) throws RuntimeException {
Double orderSize = order.getOrderSize();

Wallet wallet = walletRepository
.findWalletBy(userId, ticker)
.findByAccountIdAndTicker(userId, ticker)
.orElseThrow(()->
new DomainValidationException("Wallet not found",
List.of(new FieldError("wallet", "userId", "user might not exist"),
Expand All @@ -62,11 +62,11 @@ protected OrderInfo.SellOrderInfo extractOrderInfo(Order order) {

public SellOrderStrategy(PublishOrderCreatedPort publishOrderCreatedPort,
AssetService assetService,
OrderWalletRepository orderWalletRepository,
OrderAccountRepository orderAccountRepository,
WalletRepository walletRepository,
AccountRepository accountRepository,
SellOrderRepository sellOrderRepository,
CreateSellOrderDomainService createOrderDomainService) {
super(publishOrderCreatedPort, assetService, orderWalletRepository, orderAccountRepository);
super(publishOrderCreatedPort, assetService, walletRepository, accountRepository);
this.sellOrderRepository = sellOrderRepository;
this.createOrderDomainService = createOrderDomainService;
}
Expand Down
Loading
Loading