-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
…rrency feature : 웨이팅 생성 시 동시성 구현하기
- Loading branch information
Showing
10 changed files
with
152 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
src/main/java/com/prgrms/catchtable/shop/repository/ShopRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,27 @@ | ||
package com.prgrms.catchtable.shop.repository; | ||
|
||
import com.prgrms.catchtable.shop.domain.Shop; | ||
import jakarta.persistence.LockModeType; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.EntityGraph; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Lock; | ||
import org.springframework.data.jpa.repository.Modifying; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.data.repository.query.Param; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
public interface ShopRepository extends JpaRepository<Shop, Long>, ShopRepositoryCustom { | ||
|
||
@EntityGraph(attributePaths = {"menuList"}) | ||
Optional<Shop> findShopById(Long id); | ||
|
||
@Lock(LockModeType.PESSIMISTIC_WRITE) | ||
@Query("select s from Shop s where s.id = :id") | ||
Optional<Shop> findByIdWithPessimisticLock(@Param("id") Long id); | ||
|
||
@Transactional | ||
@Modifying(clearAutomatically = true) | ||
@Query("update Shop s set s.waitingCount = 0") | ||
void initWaitingCount(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,7 @@ void setUp() { | |
memberRepository.saveAll(List.of(member1, member2, member3)); | ||
|
||
shop = ShopFixture.shopWith24(); | ||
ReflectionTestUtils.setField(shop, "waitingCount", 3); | ||
shopRepository.save(shop); | ||
|
||
Owner owner = OwnerFixture.getOwner("[email protected]", "owner"); | ||
|
@@ -145,7 +146,6 @@ void createWaitingSuccess() throws Exception { | |
|
||
waiting1.changeStatusCanceled(); | ||
waitingRepository.save(waiting1); | ||
|
||
// when, then | ||
mockMvc.perform(post("/waitings/{shopId}", shop.getId()) | ||
.contentType(APPLICATION_JSON) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
src/test/java/com/prgrms/catchtable/waiting/service/MemberWaitingServiceIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package com.prgrms.catchtable.waiting.service; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
import com.prgrms.catchtable.member.MemberFixture; | ||
import com.prgrms.catchtable.member.domain.Member; | ||
import com.prgrms.catchtable.member.repository.MemberRepository; | ||
import com.prgrms.catchtable.owner.domain.Owner; | ||
import com.prgrms.catchtable.owner.fixture.OwnerFixture; | ||
import com.prgrms.catchtable.owner.repository.OwnerRepository; | ||
import com.prgrms.catchtable.shop.domain.Shop; | ||
import com.prgrms.catchtable.shop.fixture.ShopFixture; | ||
import com.prgrms.catchtable.shop.repository.ShopRepository; | ||
import com.prgrms.catchtable.waiting.dto.request.CreateWaitingRequest; | ||
import com.prgrms.catchtable.waiting.fixture.WaitingFixture; | ||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Disabled; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.data.redis.core.StringRedisTemplate; | ||
|
||
@SpringBootTest | ||
@Disabled | ||
class MemberWaitingServiceIntegrationTest { | ||
|
||
@Autowired | ||
private ShopRepository shopRepository; | ||
@Autowired | ||
private OwnerRepository ownerRepository; | ||
@Autowired | ||
private MemberRepository memberRepository; | ||
@Autowired | ||
private MemberWaitingService memberWaitingService; | ||
|
||
@Autowired | ||
private StringRedisTemplate redisTemplate; | ||
|
||
private Shop shop; | ||
private CreateWaitingRequest request; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
request = WaitingFixture.createWaitingRequest(); | ||
|
||
shop = ShopFixture.shopWith24(); | ||
shopRepository.save(shop); | ||
|
||
Owner owner = OwnerFixture.getOwner(shop); | ||
ownerRepository.save(owner); | ||
} | ||
|
||
@AfterEach | ||
void clear() { | ||
redisTemplate.delete("s" + shop.getId()); | ||
} | ||
|
||
@DisplayName("동시에 30개 요청이 들어와도 각각 다른 대기번호를 부여한다.") | ||
@Test | ||
void createWaitingNumberConcurrency() throws InterruptedException { | ||
int threadCount = 30; | ||
ExecutorService executorService = Executors.newFixedThreadPool(30); | ||
CountDownLatch latch = new CountDownLatch( | ||
threadCount); // 다른 thread에서 수행 중인 작업이 완료될 때까지 대기할 수 있도록 돕는 클래스 | ||
for (int i = 0; i < threadCount; i++) { | ||
Member member = MemberFixture.member(String.format("hyun%[email protected]", | ||
i)); // validateMemberWaitingExists 오류 안 나도록 (한 기기 당 한 회원 웨이팅 생성) | ||
memberRepository.save(member); | ||
|
||
executorService.submit(() -> { | ||
try { | ||
memberWaitingService.createWaiting(shop.getId(), member, request); | ||
} finally { | ||
latch.countDown(); | ||
} | ||
}); | ||
} | ||
|
||
latch.await(); //다른 스레드에서 수행중인 작업이 완료될 때까지 대기 | ||
int waitingCount = shopRepository.findAll().get(0) | ||
.getWaitingCount(); | ||
assertEquals(threadCount, waitingCount); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters