묻고 답해요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
@Transactional, synchronized를 동시에 사용하면 재고수량 감소 로직 동시성이 궁금합니다ㅠㅠ
StockService.decrease 메소드의 경우synchronized 가 붙어있어서 하나의 쓰레드만 들어갈 수 있도록 도와주지만,@Transactional 이 붙어있기에 froxy 객체로 만들어서 동시성이 안됨을 아래 테스트코드로 확인하였습니다. 하지만 똑같은 StockService.decrease를 사용하여CompletableFuture.runAsync를 사용하면 동시성이 보장이됩니다..똑같이 @Transactional을 사용한 decrease메소드라서 froxy객체로 만들어져서 동시성이 보장 안될것이라 예측했는데 왜 CompletableFuture.runAsync는 동시성 보장이 될까 궁금합니다ㅠㅠ
-
해결됨재고시스템으로 알아보는 동시성이슈 해결방법
Lettuce를 활용한 방법에서 Stock 엔티티에 @Version가 없어도 되죠?
DB의 Named Lock을 활용하기 위한 방법에서 쓰였던 것인데 지워도 되는 거죠?
-
미해결성공적인 진짜 iOS 개발자 되기 [기초부터 실무까지]
self.navigationBar.topItem?.leftBarButtonItem을 해도 button이 보이지 않습니다
강사님의 코드와 똑같이 코드를 구성했는데 버튼이 보이지 않습니다addsubView방식은 보이는 상황입니다 ㅠㅠ혹시 바뀐부분이있는걸까요
-
해결됨재고시스템으로 알아보는 동시성이슈 해결방법
Redisson Client Lock
public void buy(String ticketName) throws InterruptedException { RLock lock = redissonClient.getLock(ticketName); try { boolean available = lock.tryLock(5, 1, TimeUnit.SECONDS); if (!available) { return; } ticketServiceWithRedisRedissonClientLock.buy(ticketName); } finally { if (lock.isLocked() && lock.isHeldByCurrentThread()) { lock.unlock(); } } }이 구조에서 tryLock에 대해서 5초동안 Lock 획득을 위해서 대기하고 Lock을 1초동안 점유하고 release하는 형식으로 알고있는데 만약에 쓰레드가 5초 동안 대기를 하더라도 최종적으로 Lock을 얻지 못한다면 return이 됨으로써 buy로직으로 못들어가는거 아닌가요?? 만약에 반드시 Lock을 얻고 buy로 들어가야만 하는 경우 Lock 재획득에 대한 로직을 따로 구현해야 하는건가요. 아니면 tryLock의 재시도에 대해서 제가 모르는 부분이 있는건가요?? public void buy(String ticketName) throws InterruptedException { final RLock lock = redissonClient.getLock(ticketName); final int maxRetryCount = 10; final int retryIntervalMillis = 1000; try { int retryCount = 0; boolean lockAcquired = lock.tryLock(5, 1, TimeUnit.SECONDS); while (!lockAcquired && retryCount < maxRetryCount) { log.info( "--> Thread [{}] Redis Distributed Lock (Redisson Client) 획득 대기", Thread.currentThread().getName() ); Thread.sleep(retryIntervalMillis); lockAcquired = lock.tryLock(5, 1, TimeUnit.SECONDS); retryCount++; } if (!lockAcquired) { log.info( "--> Thread [{}] Redis Distributed Lock (Redisson Client) 획득 실패", Thread.currentThread().getName() ); return; } ticketServiceWithRedisRedissonClientLock.buy(ticketName); } finally { if (lock.isLocked() && lock.isHeldByCurrentThread()) { lock.unlock(); } } }이런 방식으로 최대 재시도 횟수와 재시도 간 간격을 통해서 waitTime동안 Lock을 못얻을 경우 Lock자체를 다시 얻는 방식을 구현해보았고 waitTime=1, unit=ms로 변경하고 테스트했을 경우 정상적으로 retry가 됨을 확인했습니다. 이런 구조가 최선일까요??아니면 더 나은 방식이 있을까요?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)
모듈 인식
윈도우10 입니다 강의 영상대로 따라하고 있었는데 flask 실행하는 부분 python hello.py 실행 xpython3 hello.py 실행orequests 실행하는 부분python hello.py 실행opython3 hello.py 실행 x같은 가상환경인데 flask 실행할때는 python에 3을 붙여야 실행하고 requests에서는 python에 3을 붙이지 않아야 실행을 하는데 같은 py파일에 코드만 바꿔서 했는데 이러는데 왜 이러는건가요...?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)
cput 바운드 01-1 질문입니다
나오는 값이 너무 많아서 정수형 4300제한이라고 나옵니다 그래서 입력값에 50이 아닌 낮은 숫자를 넣으면 실행은 되는데요 정수형 제한을 풀려면 sys를 써야 하는 걸로 아는데 그 부분은 코드에 없어서 그러는데 혹시 어떻게 하셨나요?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)
await 위치 질문
안녕하세요, await 위치를 완전히 이해하지 못한 것 같아 질문드립니다.제가 이해한 await란 비동기 함수 내에서 특정 객체가 끝날때까지 기다려서 결과를 반환하기 위해 사용하는 것인데요. 이를 간단하게 말하자면 비동기 함수 내에서 동시성을 가지고 처리해야 할 부분(= 탈출해야할 부분) 앞에 기다리라는 의미로 await를 쓴다고 이해한 것이 맞을까요?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)
실전 프로젝트 최종 디렉토리 문의
안녕하세요,마지막 실전 프로젝트에서 디렉토리가 많은데, 어떤 것이 최종일까요? 9번이 강의 내용으로는 최종인 것 같은데 디렉토리 구조가 좀 다른 것 같아서요.
-
미해결고수가 되는 파이썬 : 동시성과 병렬성 문법 배우기 Feat. 멀티스레딩 vs 멀티프로세싱 (Inflearn Original)
1-3강의 내용중 질문있습니다.
전반적인 내용은 이해를 했는데 포매팅에 대한 이해도가 아직 부족한것 같습니다.. 강의 코드 중 format = "%(asctime)s: %(message)s" logging.basicConfig(format=format, level=logging.INFO, datefmt="%H:%M:%S")이런 코드가 있었는데요, 왜 date포맷 형식이 출력될때는 먼저 나오나요? asctime이라는 저 포맷 형태가 자동으로 datefmt를 인식해서 그런건가요?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)
6-4 03:57~ hhh 질문입니다!
페이지의 Item ID: hhh에서 hhh는 어떤 파일의 어느 부분에서 입력되는건지 궁금합니다!
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
수행 시간 비교 관련 질문
안녕하세요 좋은 강의 해주셔서 감사합니다.강의를 전부 듣고 각 방식의 성능이 궁금하여 이를 찍어보았는데 조금 의아한 결과가 나와서 질문 드립니다.동시성 처리 안한 버전 256 mssynchronized 버전 962 ms비관적락 468 ms낙관적락 1441 msNamedLock 807 msLettuceLock 4184 msRedissonLock 1137 ms 몇번씩 테스트해본 결과 대략 위와 같은 정도의 성능이 나옵니다. 처음 생각하기로는 Redis 사용 방식이 비교적 빠를것이고, DB에 락을 거는 방식이 Redis에 비해 느리지 않을까 했는데 오히려 반대로 DB에 락을 거는게 빠르고 Redis를 사용하는 방식이 느린것을 확인할 수 있었습니다. 혹시 이러한 결과가 나오게 된 이유를 여쭤볼 수 있을까요? 감사합니다.
-
해결됨재고시스템으로 알아보는 동시성이슈 해결방법
프록시 객체가 생성될 때 synchronized 없이 메서드가 생성되는 것이 맞을까요?
먼저 좋은 강의 감사드립니다. 프록시 객체에서 이해가 안 가는 부분이 있어 질문드립니다.@Transactional을 사용하면 프록시 방식의 AOP로 동작하는 것은 이해하고 있습니다. 스프링 부트는 CGLIB 방식으로 프록시 객체를 생성하므로, StockService를 상속하는 StockServiceProxy가 만들어질 때 StockServiceProxy.decrease()에도 synchronized 키워드가 붙어있을 것이라고 생각했습니다. 그런데 강사님께서 TransactionStockService 를 예로 드실 때 synchronized 를 안 붙이신 걸 보니 프록시 객체가 생성될 때는 synchronized 가 안 붙는 건가? 라고 생각들었습니다.Q. 프록시 객체가 생성될 때 synchronized 없이 메서드가 생성되는 것이 맞을까요?읽어주셔서 감사합니다 :)
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
재고 데이터를 Redis에서 관리했을 때 분산락의 필요성
현재 강의에서 재고 데이터를 MySQL에서 관리하고 있는데, 만약에 다중 서버 환경이라고 가정하고, 재고 데이터를 Redis에서 관리한다했을 때에도 분산락이 필요한건가요? 제가 redisson을 이용해서 재고 감소 시키는 로직과 redisson을 이용하지 않고 재고 감소 시키는 로직을 구현했는데, 제가 예상한 바로는 redisson을 이용하지 않고 재고 감소 시킬 때에는 데이터 정합성이 맞지 않고, redisson을 이용해서 재고 감소시키는 로직에선느 데이터 정합성이 맞을 것이다라고 생각했는데, 결과는 둘다 동일하게 데이터 정합성이 맞더라구요. 왜 그런걸까요? 1번째 코드는 구현코드고, 2번째 코드는 테스트 코드입니다. @Repository public class InventoryRepository { private final RedisStringsRepository redisStringsRepository; private final RedissonClient redissonClient; private int waitTimeForAcquiringLock = 1; private int leaseTimeForLock = 1; @Autowired public InventoryCommandRepository( RedisStringsRepository redisStringsRepository, RedissonClient redissonClient ) { this.redisStringsRepository = redisStringsRepository; this.redissonClient = redissonClient; } public void set(String key, int amount) { redisStringsRepository.set(key, String.valueOf(amount)); } public void delete(String key) { redisStringsRepository.delete(key); } // lock 없이 재고 로직 감소 public void decreaseByAmountWithoutLock(String key, int amount) { redisStringsRepository.decreaseByAmount(key, Long.valueOf(amount)); } // lock 하고 재고 로직 감소 public void decreaseByAmount(String key, int amount) { RLock rlock = redissonClient.getLock(key+"lock"); try { boolean available = rlock.tryLock(waitTimeForAcquiringLock, leaseTimeForLock, TimeUnit.SECONDS); if (!available) { System.out.println("lock 획득 실패 "); return; } redisStringsRepository.decreaseByAmount(key, Long.valueOf(amount)); } catch (InterruptedException e) { throw new RuntimeException(e); if (rlock != null && rlock.isLocked()) { rlock.unlock(); } } } } @DisplayName("InventoryRepository") @SpringBootTest public class InventoryRepositoryTest { @Autowired private InventoryRepository inventoryRepository; @Autowired private RedisStringsRepository redisStringsRepository; @Autowired private RedisTemplate<String, String> redisTemplate; String key = "testKey"; int initialAmount = 100; @BeforeEach public void setUp() { redisStringsRepository.set(key, String.valueOf(initialAmount)); } @AfterEach void teardown() { redisStringsRepository.delete(key); } @Nested @DisplayName("decreaseByAmountWithoutLock") class Describe_decreaseByAmountWithoutLock { @Nested @DisplayName("with 1 thread") class Context_With_Single_Thread { @Test @DisplayName("decreases inventory by amount") void It_Decreases_Inventory_By_Amount() throws InterruptedException { int decreaseAmount = 1; inventoryRepository.decreaseByAmountWithoutLock(key, decreaseAmount); String value = redisStringsRepository.get(key); int expectedAmount = initialAmount - decreaseAmount; assertEquals(expectedAmount, Integer.valueOf(value)); } } @Nested @DisplayName("with multi thread") class Context_With_Multi_Thread { @Test @DisplayName("does not decrease inventory by amount") void It_Does_Not_Decrease_Inventory_By_Amount() throws InterruptedException { int threadCount = 100; int decreaseAmount = 1; ExecutorService executorService = Executors.newFixedThreadPool(32); CountDownLatch latch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { executorService.submit(() -> { try { // Perform the test inventoryRepository.decreaseByAmountWithoutLock(key, decreaseAmount); } catch (Exception e) { System.out.println(e.getMessage()); } finally { latch.countDown(); } }); } latch.await(); String value = redisStringsRepository.get(key); assertNotEquals(0, Integer.valueOf(value)); // 테스트 통과 안함. } } } @Nested @DisplayName("decreaseByAmount") class Describe_decreaseByAmount { @Nested @DisplayName("with 1 thread") class Context_With_Single_Thread { @Test @DisplayName("decreases inventory by amount") void It_Decreases_Inventory_By_Amount() throws InterruptedException { int decreaseAmount = 1; inventoryRepository.decreaseByAmount(key, decreaseAmount); String value = redisStringsRepository.get(key); int expectedAmount = initialAmount - decreaseAmount; assertEquals(expectedAmount, Integer.valueOf(value)); } } @Nested @DisplayName("with multi thread") class Context_With_Multi_Thread { @Test @DisplayName("decrease inventory by amount") void It_Does_Not_Decrease_Inventory_By_Amount() throws InterruptedException { int threadCount = 100; int decreaseAmount = 1; ExecutorService executorService = Executors.newFixedThreadPool(32); CountDownLatch latch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { executorService.submit(() -> { try { // Perform the test inventoryRepository.decreaseByAmount(key, decreaseAmount); } catch (Exception e) { System.out.println(e.getMessage()); } finally { latch.countDown(); // Latch의 숫자가 1개씩 감소 } }); } latch.await(); // Latch의 숫자가 0이 될 때까지 기다리는 코드 String value = redisStringsRepository.get(key); assertEquals(0, Integer.valueOf(value)); } } } }
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)
await asyncio.gather 메소드 안에서 마지막 delivery 함수 이후에 , 를 추가하는 이유가 뭘까요?
결과 값은 같아 보이는데 아래 이미지에서 마지막에 ,를 추가한 이유가 있을까요?
-
미해결운영체제 공룡책 강의
1.운영체제가 뭐길래 7분 58초 질문이요
1.운영체제가 뭐길래 에서 7분58초에 1Mb를 2의 1024승이라고 말씀하셨는데, 찾아보니 1Kb가 2의 1024승 이던데요... 제가 잘못찾은걸까요?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)
코루틴 활용 런타임에러
안녕하세요 코루틴 활용 파트에서코드를 실행해보니raise RuntimeError('Event loop is closed')RuntimeError: Event loop is closed라고 문구가 뜨네요..aiohttp 3.7.3 버전 인스톨하는데 3.7.4.post0으로 다운이 되었구요. 해결책 좀 알려주시면 감사하겠습니다.
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)
언패킹 관련 질문입니다.
안녕하세요.04-2-coroutine-fetcher.py에서 fetcher 함수에서 url을 언패킹하실 때 *를 사용하셨는데 아래 코드에서 가 어떻게 작동하는건지 알 수 있을까요?result = await asyncio.gather(*[fetcher(session, url) for url in urls])
-
해결됨재고시스템으로 알아보는 동시성이슈 해결방법
다양한 방법 알아보기 문서내용 다름
다양한 방법 알아보기 의 문서내용이 화면에서 나오는 내용과 다르네요. 확인 부탁드립니다.
-
미해결앨런 iOS 앱 개발 (15개의 앱을 만들면서 근본원리부터 배우는 UIKit) - MVVM까지
섹션 15 동기와 비동기의 개념 질문있습니다
강의를 듣던 도중 동기 , 비동기, 직렬, 동시 에 개념에 대해서 질문이 생겼습니다.직렬의 경우 그림으로 표현해 주셨던 것처럼다른 하나의 쓰레드에서 task를 순서에 따라 전부 다 처리한다고 이해했는데,제가 이해한 것이 맞다면, 동기 방식으로 직렬 테스크를 처리했을 때 굳이 다른쓰레드로 테스크를 넘기는 것이 의미가 있나요? 비동기라면 해당 테스크를 직렬로 처리하더라도 동시에 다른 테스크를 진행할 수 있다고 생각하지만 동기처리의 경우 결국 메인쓰레드에서 진행하는 것과 같은 수준의 처리시간이 들고 오히려 쓰레드를 바꾸는데에 대한 리소스만 더 사용하게 되는것은 아닌가요??라는 의문이 들었습니다..!
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
Redisson import
안녕하세요.Build.gradle에 Redisson을 import하는 과정에서 궁금증이 생겨서 질문합니다.처음에 Redisson을 검색해서 import를 했는데 Facade에서 생성자를 만들때 빨간줄이 뜨고, test를 돌려보니 에러가 나더라구요.importimplementation group: 'org.redisson', name: 'redisson', version: '3.2.0'import한 페이지https://mvnrepository.com/artifact/org.redisson/redisson/3.2.0생성자 경고 test errorjava.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@3f908a10 testClass = com.example.stock.facade.RedissonLockFacadeTest, locations = [], classes = [com.example.stock.StockApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceLocations = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@9da1, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@16a0ee18, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@bd4dc25, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@71def8f8, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1da2cb77, org.springframework.boot.test.context.SpringBootTestAnnotation@818c3651], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:142) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:127) at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:191) at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:130) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:241) at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$10(ClassBasedTestDescriptor.java:377) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:382) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$11(ClassBasedTestDescriptor.java:377) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:376) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:289) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:288) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:278) at java.base/java.util.Optional.orElseGet(Optional.java:364) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:277) at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:105) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:104) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:68) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redissonLockFacade' defined in file [/Users/jialee/inflearn/stock/out/production/classes/com/example/stock/facade/RedissonLockFacade.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'org.redisson.api.RedissonClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798) 그래서 다시 검색해서 import 하니 생성자쪽에서 빨간줄은 뜨지 않지만, 테스트를 돌리면 동일한 에러가 나더라구요.importimplementation 'org.redisson:redisson-spring-boot-starter:3.17.4'혹시 두 inport의 차이점은 무엇이며, 왜 계속 테스트가 실패하는건지도 문의드립니다. + 추가로 git 주소도 남깁니다.https://github.com/uiop9900/stock.git