diff --git a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ReleaseQueryGrpcAdapter.java b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ReleaseQueryGrpcAdapter.java index fdeb06c2..18bc5818 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ReleaseQueryGrpcAdapter.java +++ b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ReleaseQueryGrpcAdapter.java @@ -1,6 +1,8 @@ package kr.magicbox.creator.adapter.out.communication.grpc; +import com.google.common.util.concurrent.ListenableFuture; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; import io.grpc.ManagedChannel; import kr.magicbox.creator.adapter.out.communication.ServiceHost; import kr.magicbox.creator.adapter.out.communication.grpc.exception.ReleaseServiceUnavailableException; @@ -19,7 +21,8 @@ import org.springframework.stereotype.Component; import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; @Component @RequiredArgsConstructor @@ -29,59 +32,68 @@ public class ReleaseQueryGrpcAdapter implements ReleaseQueryPort { @Override @CircuitBreaker(name = "releaseService", fallbackMethod = "getReleaseCountFallback") - public long getReleaseCount(Long creatorId) { + @TimeLimiter(name = "releaseService", fallbackMethod = "getReleaseCountFallback") + public CompletableFuture getReleaseCount(Long creatorId) { GetReleaseCountRequest request = GetReleaseCountRequest.newBuilder() .setCreatorId(creatorId) .build(); ManagedChannel channel = grpcChannelFactory.createChannel(ServiceHost.RELEASE.getHostName()); - ReleaseServiceGrpc.ReleaseServiceBlockingStub stub = ReleaseServiceGrpc - .newBlockingStub(channel) - .withDeadlineAfter(2, TimeUnit.SECONDS); - GetReleaseCountResponse response = stub.getReleaseCount(request); - - return response.getReleaseCount(); + ReleaseServiceGrpc.ReleaseServiceFutureStub stub = ReleaseServiceGrpc.newFutureStub(channel); + ListenableFuture future = stub.getReleaseCount(request); + try { + GetReleaseCountResponse response = future.get(); + return CompletableFuture.completedFuture(response.getReleaseCount()); + } catch (ExecutionException e) { + return CompletableFuture.failedFuture(e.getCause()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return CompletableFuture.failedFuture(e); + } } @Override @CircuitBreaker(name = "releaseService", fallbackMethod = "getReleasesFallback") - public List getReleases(Long creatorId) { + @TimeLimiter(name = "releaseService", fallbackMethod = "getReleasesFallback") + public CompletableFuture> getReleases(Long creatorId) { GetReleasesByCreatorIdRequest request = GetReleasesByCreatorIdRequest.newBuilder() .setCreatorId(creatorId) .build(); ManagedChannel channel = grpcChannelFactory.createChannel(ServiceHost.RELEASE.getHostName()); - ReleaseServiceGrpc.ReleaseServiceBlockingStub stub = ReleaseServiceGrpc - .newBlockingStub(channel) - .withDeadlineAfter(2, TimeUnit.SECONDS); - GetReleasesByCreatorIdResponse response = stub.getReleasesByCreatorId(request); - - return response.getReleasesList().stream() - .map(release -> ReleaseResult.builder() - .releaseId(ReleaseId.of(release.getReleaseId())) - .title(release.getTitle()) - .thumbnailUrl(release.getThumbnailUrl()) - .level(ReleaseLevel.valueOf(release.getLevel().name())) - .creatorNickname(release.getCreatorNickname()) - .price(release.getPrice()) - .limitedQuantity(release.getLimitedQuantity()) - .build()) - .toList(); + ReleaseServiceGrpc.ReleaseServiceFutureStub stub = ReleaseServiceGrpc.newFutureStub(channel); + ListenableFuture future = stub.getReleasesByCreatorId(request); + try { + GetReleasesByCreatorIdResponse response = future.get(); + List releases = response.getReleasesList().stream() + .map(release -> ReleaseResult.builder() + .releaseId(ReleaseId.of(release.getReleaseId())) + .title(release.getTitle()) + .thumbnailUrl(release.getThumbnailUrl()) + .level(ReleaseLevel.valueOf(release.getLevel().name())) + .creatorNickname(release.getCreatorNickname()) + .price(release.getPrice()) + .limitedQuantity(release.getLimitedQuantity()) + .build()) + .toList(); + return CompletableFuture.completedFuture(releases); + } catch (ExecutionException e) { + return CompletableFuture.failedFuture(e.getCause()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return CompletableFuture.failedFuture(e); + } } @SuppressWarnings("unused") - private long getReleaseCountFallback(Long creatorId, Throwable throwable) { + private CompletableFuture getReleaseCountFallback(Long creatorId, Throwable throwable) { log.warn("릴리즈 개수 조회 서비스 연결 실패"); throw new ReleaseServiceUnavailableException(throwable); } @SuppressWarnings("unused") - private List getReleasesFallback(Long creatorId, Throwable throwable) { - throw buildReleaseServiceUnavailableException(throwable); - } - - private ReleaseServiceUnavailableException buildReleaseServiceUnavailableException(Throwable throwable) { + private CompletableFuture> getReleasesFallback(Long creatorId, Throwable throwable) { log.warn("릴리즈 목록 조회 서비스 연결 실패"); - return new ReleaseServiceUnavailableException(throwable); + throw new ReleaseServiceUnavailableException(throwable); } } diff --git a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ReviewQueryGrpcAdapter.java b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ReviewQueryGrpcAdapter.java index 0181628a..ad65aaef 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ReviewQueryGrpcAdapter.java +++ b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ReviewQueryGrpcAdapter.java @@ -1,6 +1,8 @@ package kr.magicbox.creator.adapter.out.communication.grpc; +import com.google.common.util.concurrent.ListenableFuture; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; import io.grpc.ManagedChannel; import kr.magicbox.creator.adapter.out.communication.ServiceHost; import kr.magicbox.creator.adapter.out.communication.grpc.exception.ReviewServiceUnavailableException; @@ -14,7 +16,8 @@ import org.springframework.grpc.client.GrpcChannelFactory; import org.springframework.stereotype.Component; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; @Component @RequiredArgsConstructor @@ -24,23 +27,29 @@ public class ReviewQueryGrpcAdapter implements ReviewRatingQueryPort { @Override @CircuitBreaker(name = "reviewService", fallbackMethod = "getReviewRatingFallback") - public ReviewRating getReviewRating(Long creatorId) { + @TimeLimiter(name = "reviewService", fallbackMethod = "getReviewRatingFallback") + public CompletableFuture getReviewRating(Long creatorId) { GetReviewRatingRequest request = GetReviewRatingRequest.newBuilder() .setCreatorId(creatorId) .build(); ManagedChannel channel = grpcChannelFactory.createChannel(ServiceHost.REVIEW.getHostName()); - ReviewServiceGrpc.ReviewServiceBlockingStub stub = ReviewServiceGrpc - .newBlockingStub(channel) - .withDeadlineAfter(2, TimeUnit.SECONDS); - GetReviewRatingResponse response = stub.getReviewRating(request); - - return ReviewRating.of(response.getRating()); + ReviewServiceGrpc.ReviewServiceFutureStub stub = ReviewServiceGrpc.newFutureStub(channel); + ListenableFuture future = stub.getReviewRating(request); + try { + GetReviewRatingResponse response = future.get(); + return CompletableFuture.completedFuture(ReviewRating.of(response.getRating())); + } catch (ExecutionException e) { + return CompletableFuture.failedFuture(e.getCause()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return CompletableFuture.failedFuture(e); + } } @SuppressWarnings("unused") - private ReviewRating getReviewRatingFallback(Long creatorId, Throwable throwable) { + private CompletableFuture getReviewRatingFallback(Long creatorId, Throwable throwable) { log.warn("리뷰 서비스 연결 실패"); throw new ReviewServiceUnavailableException(throwable); } -} \ No newline at end of file +} diff --git a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ShortformQueryGrpcAdapter.java b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ShortformQueryGrpcAdapter.java index 61d133f5..48e4eb00 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ShortformQueryGrpcAdapter.java +++ b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/ShortformQueryGrpcAdapter.java @@ -1,12 +1,14 @@ package kr.magicbox.creator.adapter.out.communication.grpc; +import com.google.common.util.concurrent.ListenableFuture; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; import io.grpc.ManagedChannel; import kr.magicbox.creator.adapter.out.communication.ServiceHost; import kr.magicbox.creator.adapter.out.communication.grpc.exception.ShortformServiceUnavailableException; +import kr.magicbox.creator.application.dto.result.ShortformId; import kr.magicbox.creator.application.dto.result.ShortformResult; import kr.magicbox.creator.application.port.out.ShortformQueryPort; -import kr.magicbox.creator.application.dto.result.ShortformId; import kr.magicbox.creator.grpc.shortform.GetShortformsByCreatorIdRequest; import kr.magicbox.creator.grpc.shortform.GetShortformsByCreatorIdResponse; import kr.magicbox.creator.grpc.shortform.ShortformServiceGrpc; @@ -16,7 +18,8 @@ import org.springframework.stereotype.Component; import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; @Component @RequiredArgsConstructor @@ -26,30 +29,37 @@ public class ShortformQueryGrpcAdapter implements ShortformQueryPort { @Override @CircuitBreaker(name = "shortformService", fallbackMethod = "getShortformsFallback") - public List getShortforms(Long creatorId) { + @TimeLimiter(name = "shortformService", fallbackMethod = "getShortformsFallback") + public CompletableFuture> getShortforms(Long creatorId) { GetShortformsByCreatorIdRequest request = GetShortformsByCreatorIdRequest.newBuilder() .setCreatorId(creatorId) .build(); ManagedChannel channel = grpcChannelFactory.createChannel(ServiceHost.SHORTFORM.getHostName()); - ShortformServiceGrpc.ShortformServiceBlockingStub stub = ShortformServiceGrpc - .newBlockingStub(channel) - .withDeadlineAfter(2, TimeUnit.SECONDS); - GetShortformsByCreatorIdResponse response = stub.getShortformsByCreatorId(request); - - return response.getShortformsList().stream() - .map(shortform -> ShortformResult.builder() - .shortformId(ShortformId.of(shortform.getShortformId())) - .title(shortform.getTitle()) - .thumbnailUrl(shortform.getThumbnailUrl()) - .videoUrl(shortform.getVideoUrl()) - .viewCount(shortform.getViewCount()) - .build()) - .toList(); + ShortformServiceGrpc.ShortformServiceFutureStub stub = ShortformServiceGrpc.newFutureStub(channel); + ListenableFuture future = stub.getShortformsByCreatorId(request); + try { + GetShortformsByCreatorIdResponse response = future.get(); + List shortforms = response.getShortformsList().stream() + .map(shortform -> ShortformResult.builder() + .shortformId(ShortformId.of(shortform.getShortformId())) + .title(shortform.getTitle()) + .thumbnailUrl(shortform.getThumbnailUrl()) + .videoUrl(shortform.getVideoUrl()) + .viewCount(shortform.getViewCount()) + .build()) + .toList(); + return CompletableFuture.completedFuture(shortforms); + } catch (ExecutionException e) { + return CompletableFuture.failedFuture(e.getCause()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return CompletableFuture.failedFuture(e); + } } @SuppressWarnings("unused") - private List getShortformsFallback(Long creatorId, Throwable throwable) { + private CompletableFuture> getShortformsFallback(Long creatorId, Throwable throwable) { log.warn("숏폼 서비스 연결 실패"); throw new ShortformServiceUnavailableException(throwable); } diff --git a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/SubscribeGrpcAdapter.java b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/SubscribeGrpcAdapter.java index 1aa48ed6..95a87715 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/SubscribeGrpcAdapter.java +++ b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/SubscribeGrpcAdapter.java @@ -1,6 +1,8 @@ package kr.magicbox.creator.adapter.out.communication.grpc; +import com.google.common.util.concurrent.ListenableFuture; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; import io.grpc.ManagedChannel; import kr.magicbox.creator.adapter.out.communication.ServiceHost; import kr.magicbox.creator.adapter.out.communication.grpc.exception.SubscribeServiceUnavailableException; @@ -15,7 +17,8 @@ import org.springframework.grpc.client.GrpcChannelFactory; import org.springframework.stereotype.Component; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; @Component @RequiredArgsConstructor @@ -25,46 +28,58 @@ public class SubscribeGrpcAdapter implements SubscribeQueryPort { @Override @CircuitBreaker(name = "subscribeService", fallbackMethod = "getSubscriberCountFallback") - public long getSubscriberCount(Long creatorId) { + @TimeLimiter(name = "subscribeService", fallbackMethod = "getSubscriberCountFallback") + public CompletableFuture getSubscriberCount(Long creatorId) { GetSubscriberCountRequest request = GetSubscriberCountRequest.newBuilder() .setCreatorId(creatorId) .build(); ManagedChannel channel = grpcChannelFactory.createChannel(ServiceHost.SUBSCRIBE.getHostName()); - SubscribeServiceGrpc.SubscribeServiceBlockingStub stub = SubscribeServiceGrpc - .newBlockingStub(channel) - .withDeadlineAfter(2, TimeUnit.SECONDS); - GetSubscriberCountResponse response = stub.getSubscriberCount(request); - - return response.getSubscriberCount(); + SubscribeServiceGrpc.SubscribeServiceFutureStub stub = SubscribeServiceGrpc.newFutureStub(channel); + ListenableFuture future = stub.getSubscriberCount(request); + try { + GetSubscriberCountResponse response = future.get(); + return CompletableFuture.completedFuture(response.getSubscriberCount()); + } catch (ExecutionException e) { + return CompletableFuture.failedFuture(e.getCause()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return CompletableFuture.failedFuture(e); + } } @Override @CircuitBreaker(name = "subscribeService", fallbackMethod = "isSubscribedFallback") - public boolean isSubscribed(Long creatorId, Long userId) { + @TimeLimiter(name = "subscribeService", fallbackMethod = "isSubscribedFallback") + public CompletableFuture isSubscribed(Long creatorId, Long userId) { IsSubscribedRequest request = IsSubscribedRequest.newBuilder() .setCreatorId(creatorId) .setUserId(userId) .build(); ManagedChannel channel = grpcChannelFactory.createChannel(ServiceHost.SUBSCRIBE.getHostName()); - SubscribeServiceGrpc.SubscribeServiceBlockingStub stub = SubscribeServiceGrpc - .newBlockingStub(channel) - .withDeadlineAfter(2, TimeUnit.SECONDS); - IsSubscribedResponse response = stub.isSubscribed(request); - - return response.getSubscribed(); + SubscribeServiceGrpc.SubscribeServiceFutureStub stub = SubscribeServiceGrpc.newFutureStub(channel); + ListenableFuture future = stub.isSubscribed(request); + try { + IsSubscribedResponse response = future.get(); + return CompletableFuture.completedFuture(response.getSubscribed()); + } catch (ExecutionException e) { + return CompletableFuture.failedFuture(e.getCause()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return CompletableFuture.failedFuture(e); + } } @SuppressWarnings("unused") - private long getSubscriberCountFallback(Long creatorId, Throwable throwable) { + private CompletableFuture getSubscriberCountFallback(Long creatorId, Throwable throwable) { log.warn("구독 서비스 연결 실패"); throw new SubscribeServiceUnavailableException(throwable); } @SuppressWarnings("unused") - private boolean isSubscribedFallback(Long creatorId, Long userId, Throwable throwable) { + private CompletableFuture isSubscribedFallback(Long creatorId, Long userId, Throwable throwable) { log.warn("구독 서비스 연결 실패"); throw new SubscribeServiceUnavailableException(throwable); } -} \ No newline at end of file +} diff --git a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/UserNicknameQueryGrpcAdapter.java b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/UserNicknameQueryGrpcAdapter.java index bd9e7cb1..2d9a79b1 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/UserNicknameQueryGrpcAdapter.java +++ b/services/creator/src/main/java/kr/magicbox/creator/adapter/out/communication/grpc/UserNicknameQueryGrpcAdapter.java @@ -1,6 +1,8 @@ package kr.magicbox.creator.adapter.out.communication.grpc; +import com.google.common.util.concurrent.ListenableFuture; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; import io.grpc.ManagedChannel; import kr.magicbox.creator.adapter.out.communication.ServiceHost; import kr.magicbox.creator.adapter.out.communication.grpc.exception.UserServiceUnavailableException; @@ -14,7 +16,8 @@ import org.springframework.grpc.client.GrpcChannelFactory; import org.springframework.stereotype.Component; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; @Component @RequiredArgsConstructor @@ -24,23 +27,29 @@ public class UserNicknameQueryGrpcAdapter implements UserNicknameQueryPort { @Override @CircuitBreaker(name = "userService", fallbackMethod = "getNicknameFallback") - public String getNickname(UserId userId) { + @TimeLimiter(name = "userService", fallbackMethod = "getNicknameFallback") + public CompletableFuture getNickname(UserId userId) { GetUserNicknameRequest request = GetUserNicknameRequest.newBuilder() .setUserId(userId.value()) .build(); ManagedChannel channel = grpcChannelFactory.createChannel(ServiceHost.USER.getHostName()); - UserServiceGrpc.UserServiceBlockingStub stub = UserServiceGrpc - .newBlockingStub(channel) - .withDeadlineAfter(2, TimeUnit.SECONDS); - GetUserNicknameResponse response = stub.getUserNickname(request); - - return response.getNickname(); + UserServiceGrpc.UserServiceFutureStub stub = UserServiceGrpc.newFutureStub(channel); + ListenableFuture future = stub.getUserNickname(request); + try { + GetUserNicknameResponse response = future.get(); + return CompletableFuture.completedFuture(response.getNickname()); + } catch (ExecutionException e) { + return CompletableFuture.failedFuture(e.getCause()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return CompletableFuture.failedFuture(e); + } } @SuppressWarnings("unused") - private String getNicknameFallback(UserId userId, Throwable throwable) { + private CompletableFuture getNicknameFallback(UserId userId, Throwable throwable) { log.warn("유저 서비스 연결 실패"); throw new UserServiceUnavailableException(throwable); } -} \ No newline at end of file +} diff --git a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ReleaseQueryPort.java b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ReleaseQueryPort.java index 1c36071a..ff127854 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ReleaseQueryPort.java +++ b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ReleaseQueryPort.java @@ -3,10 +3,11 @@ import kr.magicbox.creator.application.dto.result.ReleaseResult; import java.util.List; +import java.util.concurrent.CompletableFuture; public interface ReleaseQueryPort { - long getReleaseCount(Long creatorId); + CompletableFuture getReleaseCount(Long creatorId); - List getReleases(Long creatorId); + CompletableFuture> getReleases(Long creatorId); } diff --git a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ReviewRatingQueryPort.java b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ReviewRatingQueryPort.java index 3cd96e27..0425e7c1 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ReviewRatingQueryPort.java +++ b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ReviewRatingQueryPort.java @@ -2,7 +2,9 @@ import kr.magicbox.creator.application.dto.result.ReviewRating; +import java.util.concurrent.CompletableFuture; + public interface ReviewRatingQueryPort { - ReviewRating getReviewRating(Long creatorId); + CompletableFuture getReviewRating(Long creatorId); } diff --git a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ShortformQueryPort.java b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ShortformQueryPort.java index 33d29da5..faf3b1fa 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ShortformQueryPort.java +++ b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/ShortformQueryPort.java @@ -3,8 +3,9 @@ import kr.magicbox.creator.application.dto.result.ShortformResult; import java.util.List; +import java.util.concurrent.CompletableFuture; public interface ShortformQueryPort { - List getShortforms(Long creatorId); + CompletableFuture> getShortforms(Long creatorId); } diff --git a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/SubscribeQueryPort.java b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/SubscribeQueryPort.java index 32aede26..f71b3a55 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/SubscribeQueryPort.java +++ b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/SubscribeQueryPort.java @@ -1,8 +1,10 @@ package kr.magicbox.creator.application.port.out; +import java.util.concurrent.CompletableFuture; + public interface SubscribeQueryPort { - long getSubscriberCount(Long creatorId); + CompletableFuture getSubscriberCount(Long creatorId); - boolean isSubscribed(Long creatorId, Long userId); + CompletableFuture isSubscribed(Long creatorId, Long userId); } diff --git a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/UserNicknameQueryPort.java b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/UserNicknameQueryPort.java index 43246b0c..402f1fa9 100644 --- a/services/creator/src/main/java/kr/magicbox/creator/application/port/out/UserNicknameQueryPort.java +++ b/services/creator/src/main/java/kr/magicbox/creator/application/port/out/UserNicknameQueryPort.java @@ -2,6 +2,8 @@ import kr.magicbox.creator.domain.vo.UserId; +import java.util.concurrent.CompletableFuture; + public interface UserNicknameQueryPort { - String getNickname(UserId userId); -} \ No newline at end of file + CompletableFuture getNickname(UserId userId); +} diff --git a/services/creator/src/main/resources/application-dev.yml b/services/creator/src/main/resources/application-dev.yml index 79a70604..34e0db92 100644 --- a/services/creator/src/main/resources/application-dev.yml +++ b/services/creator/src/main/resources/application-dev.yml @@ -47,7 +47,9 @@ spring: spring.deserializer.value.delegate.class: org.springframework.kafka.support.serializer.JacksonJsonDeserializer spring.json.trusted.packages: "kr.magicbox.creator.adapter.in.kafka.event" spring.json.type.mapping: user-withdrawn:kr.magicbox.creator.adapter.in.kafka.event.UserWithdrawnEvent,user-banned:kr.magicbox.creator.adapter.in.kafka.event.UserBannedEvent - retry: + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer topic: backoff: multiplier: 2 @@ -69,3 +71,49 @@ security: inbox: max-event-age-minutes: 5 + +resilience4j: + circuitbreaker: + instances: + userService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + subscribeService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + reviewService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + releaseService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + shortformService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + timelimiter: + instances: + userService: + timeout-duration: 2s + subscribeService: + timeout-duration: 2s + reviewService: + timeout-duration: 2s + releaseService: + timeout-duration: 2s + shortformService: + timeout-duration: 2s diff --git a/services/creator/src/main/resources/application-local.yml b/services/creator/src/main/resources/application-local.yml index 7775010e..42e94dc0 100644 --- a/services/creator/src/main/resources/application-local.yml +++ b/services/creator/src/main/resources/application-local.yml @@ -50,7 +50,9 @@ spring: spring.deserializer.value.delegate.class: org.springframework.kafka.support.serializer.JacksonJsonDeserializer spring.json.trusted.packages: "kr.magicbox.creator.adapter.in.kafka.event" spring.json.type.mapping: user-withdrawn:kr.magicbox.creator.adapter.in.kafka.event.UserWithdrawnEvent,user-banned:kr.magicbox.creator.adapter.in.kafka.event.UserBannedEvent - retry: + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer topic: backoff: multiplier: 2 @@ -77,3 +79,49 @@ security: inbox: max-event-age-minutes: 5 + +resilience4j: + circuitbreaker: + instances: + userService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + subscribeService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + reviewService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + releaseService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + shortformService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 5 + timelimiter: + instances: + userService: + timeout-duration: 2s + subscribeService: + timeout-duration: 2s + reviewService: + timeout-duration: 2s + releaseService: + timeout-duration: 2s + shortformService: + timeout-duration: 2s diff --git a/services/creator/src/main/resources/application-prod.yml b/services/creator/src/main/resources/application-prod.yml index 7e131eed..380ad287 100644 --- a/services/creator/src/main/resources/application-prod.yml +++ b/services/creator/src/main/resources/application-prod.yml @@ -47,7 +47,9 @@ spring: spring.deserializer.value.delegate.class: org.springframework.kafka.support.serializer.JacksonJsonDeserializer spring.json.trusted.packages: "kr.magicbox.creator.adapter.in.kafka.event" spring.json.type.mapping: user-withdrawn:kr.magicbox.creator.adapter.in.kafka.event.UserWithdrawnEvent,user-banned:kr.magicbox.creator.adapter.in.kafka.event.UserBannedEvent - retry: + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer topic: backoff: multiplier: 2 @@ -70,3 +72,49 @@ security: inbox: max-event-age-minutes: 60 + +resilience4j: + circuitbreaker: + instances: + userService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 30s + permitted-number-of-calls-in-half-open-state: 5 + subscribeService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 30s + permitted-number-of-calls-in-half-open-state: 5 + reviewService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 30s + permitted-number-of-calls-in-half-open-state: 5 + releaseService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 30s + permitted-number-of-calls-in-half-open-state: 5 + shortformService: + sliding-window-type: COUNT_BASED + sliding-window-size: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 30s + permitted-number-of-calls-in-half-open-state: 5 + timelimiter: + instances: + userService: + timeout-duration: 2s + subscribeService: + timeout-duration: 2s + reviewService: + timeout-duration: 2s + releaseService: + timeout-duration: 2s + shortformService: + timeout-duration: 2s diff --git a/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/in/web/SubscribeCommandController.java b/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/in/web/SubscribeCommandController.java index 6bf7f538..27a24aa0 100644 --- a/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/in/web/SubscribeCommandController.java +++ b/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/in/web/SubscribeCommandController.java @@ -25,7 +25,7 @@ public class SubscribeCommandController { @PostMapping("/{creatorId}") public ResponseEntity subscribe(@AuthenticationPrincipal UserId userId, - @PathVariable Long creatorId) { + @PathVariable Long creatorId) throws java.util.concurrent.ExecutionException, InterruptedException { subscribeUseCase.subscribe(SubscribeCommand.of(SubscriberId.of(userId.value()), CreatorId.of(creatorId))); return ResponseEntity.noContent().build(); } diff --git a/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/communication/grpc/CreatorGrpcAdapter.java b/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/communication/grpc/CreatorGrpcAdapter.java index 3498c3d1..a9f4b690 100644 --- a/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/communication/grpc/CreatorGrpcAdapter.java +++ b/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/communication/grpc/CreatorGrpcAdapter.java @@ -1,6 +1,8 @@ package kr.magicbox.subscribe.adapter.out.communication.grpc; +import com.google.common.util.concurrent.ListenableFuture; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; import io.grpc.ManagedChannel; import kr.magicbox.subscribe.adapter.out.communication.grpc.exception.CreatorServiceUnavailableException; import kr.magicbox.subscribe.application.port.out.CreatorIdentityQueryPort; @@ -13,7 +15,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; @Component @RequiredArgsConstructor @@ -23,23 +26,24 @@ public class CreatorGrpcAdapter implements CreatorIdentityQueryPort { @Override @CircuitBreaker(name = "creatorService", fallbackMethod = "isCreatorOwnedByUserFallback") - public boolean isCreatorOwnedByUser(CreatorId creatorId, SubscriberId subscriberId) { + @TimeLimiter(name = "creatorService", fallbackMethod = "isCreatorOwnedByUserFallback") + public CompletableFuture isCreatorOwnedByUser(CreatorId creatorId, SubscriberId subscriberId) throws ExecutionException, InterruptedException { IsCreatorOwnedByUserRequest request = IsCreatorOwnedByUserRequest.newBuilder() .setCreatorId(creatorId.value()) .setUserId(subscriberId.value()) .build(); - CreatorServiceGrpc.CreatorServiceBlockingStub stub = CreatorServiceGrpc.newBlockingStub(creatorManagedChannel); - IsCreatorOwnedByUserResponse response = stub.withDeadlineAfter(2, TimeUnit.SECONDS) - .isCreatorOwnedByUser(request); + CreatorServiceGrpc.CreatorServiceFutureStub stub = CreatorServiceGrpc.newFutureStub(creatorManagedChannel); + ListenableFuture future = stub.isCreatorOwnedByUser(request); + IsCreatorOwnedByUserResponse response = future.get(); - return response.getOwnedByUser(); + return CompletableFuture.completedFuture(response.getOwnedByUser()); } @SuppressWarnings("unused") - private boolean isCreatorOwnedByUserFallback(CreatorId creatorId, - SubscriberId subscriberId, - Throwable throwable) { + private CompletableFuture isCreatorOwnedByUserFallback(CreatorId creatorId, + SubscriberId subscriberId, + Throwable throwable) { log.warn("creator 서비스 연결 실패: creatorId={}, subscriberId={}", creatorId.value(), subscriberId.value(), diff --git a/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/persistence/SubscriptionJpaAdapter.java b/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/persistence/SubscriptionJpaAdapter.java index ea188684..9201f701 100644 --- a/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/persistence/SubscriptionJpaAdapter.java +++ b/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/persistence/SubscriptionJpaAdapter.java @@ -23,7 +23,7 @@ public class SubscriptionJpaAdapter implements SubscriptionRepositoryPort { public void save(Subscription subscription) { try { subscriptionJpaRepository.save(subscriptionMapper.toEntity(subscription)); - } + } catch (DataIntegrityViolationException e) { throw new AlreadySubscribedException(); } @@ -60,6 +60,19 @@ public List findAllByCreatorId(CreatorId creatorId) { .toList(); } + @Override + public List findBySubscriberIdWithCursor(SubscriberId subscriberId, Long cursorId, int size) { + return subscriptionJpaRepository.findBySubscriberIdWithCursor(subscriberId.value(), cursorId, size) + .stream() + .map(subscriptionMapper::toDomain) + .toList(); + } + + @Override + public List findCreatorIdsBySubscriberId(SubscriberId subscriberId) { + return subscriptionJpaRepository.findCreatorIdsBySubscriberId(subscriberId.value()); + } + @Override public boolean existsBySubscriberIdAndCreatorId(SubscriberId subscriberId, CreatorId creatorId) { return subscriptionJpaRepository.existsBySubscriberIdAndCreatorId(subscriberId.value(), creatorId.value()); diff --git a/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/persistence/repository/SubscriptionJpaRepository.java b/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/persistence/repository/SubscriptionJpaRepository.java index b705ac8e..1213c21d 100644 --- a/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/persistence/repository/SubscriptionJpaRepository.java +++ b/services/subscribe/src/main/java/kr/magicbox/subscribe/adapter/out/persistence/repository/SubscriptionJpaRepository.java @@ -17,6 +17,12 @@ public interface SubscriptionJpaRepository extends JpaRepository findAllByCreatorId(Long creatorId); + @Query("select s from SubscriptionEntity s where s.subscriberId = :subscriberId and (:cursorId is null or s.id < :cursorId) order by s.id desc limit :size") + List findBySubscriberIdWithCursor(@Param("subscriberId") Long subscriberId, @Param("cursorId") Long cursorId, @Param("size") int size); + + @Query("select s.creatorId from SubscriptionEntity s where s.subscriberId = :subscriberId") + List findCreatorIdsBySubscriberId(@Param("subscriberId") Long subscriberId); + void deleteBySubscriberIdAndCreatorId(Long subscriberId, Long creatorId); @Modifying(clearAutomatically = true) diff --git a/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/in/SubscribeUseCase.java b/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/in/SubscribeUseCase.java index a866b044..7840307e 100644 --- a/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/in/SubscribeUseCase.java +++ b/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/in/SubscribeUseCase.java @@ -2,6 +2,8 @@ import kr.magicbox.subscribe.application.dto.command.SubscribeCommand; +import java.util.concurrent.ExecutionException; + public interface SubscribeUseCase { - void subscribe(SubscribeCommand command); + void subscribe(SubscribeCommand command) throws ExecutionException, InterruptedException; } diff --git a/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/out/CreatorIdentityQueryPort.java b/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/out/CreatorIdentityQueryPort.java index c95e79b3..65788ba3 100644 --- a/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/out/CreatorIdentityQueryPort.java +++ b/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/out/CreatorIdentityQueryPort.java @@ -3,6 +3,9 @@ import kr.magicbox.subscribe.domain.vo.CreatorId; import kr.magicbox.subscribe.domain.vo.SubscriberId; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + public interface CreatorIdentityQueryPort { - boolean isCreatorOwnedByUser(CreatorId creatorId, SubscriberId subscriberId); + CompletableFuture isCreatorOwnedByUser(CreatorId creatorId, SubscriberId subscriberId) throws ExecutionException, InterruptedException; } diff --git a/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/out/SubscriptionRepositoryPort.java b/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/out/SubscriptionRepositoryPort.java index 946c2e21..4d5ed856 100644 --- a/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/out/SubscriptionRepositoryPort.java +++ b/services/subscribe/src/main/java/kr/magicbox/subscribe/application/port/out/SubscriptionRepositoryPort.java @@ -19,6 +19,10 @@ public interface SubscriptionRepositoryPort { List findAllByCreatorId(CreatorId creatorId); + List findBySubscriberIdWithCursor(SubscriberId subscriberId, Long cursorId, int size); + + List findCreatorIdsBySubscriberId(SubscriberId subscriberId); + boolean existsBySubscriberIdAndCreatorId(SubscriberId subscriberId, CreatorId creatorId); long countByCreatorId(CreatorId creatorId); diff --git a/services/subscribe/src/main/java/kr/magicbox/subscribe/application/service/SubscribeService.java b/services/subscribe/src/main/java/kr/magicbox/subscribe/application/service/SubscribeService.java index 0295bcd9..e56af063 100644 --- a/services/subscribe/src/main/java/kr/magicbox/subscribe/application/service/SubscribeService.java +++ b/services/subscribe/src/main/java/kr/magicbox/subscribe/application/service/SubscribeService.java @@ -11,6 +11,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.concurrent.ExecutionException; + @Service @RequiredArgsConstructor public class SubscribeService implements SubscribeUseCase { @@ -19,8 +21,8 @@ public class SubscribeService implements SubscribeUseCase { @Transactional @Override - public void subscribe(SubscribeCommand command) { - if (creatorIdentityQueryPort.isCreatorOwnedByUser(command.creatorId(), command.subscriberId())) { + public void subscribe(SubscribeCommand command) throws ExecutionException, InterruptedException { + if (creatorIdentityQueryPort.isCreatorOwnedByUser(command.creatorId(), command.subscriberId()).get()) { throw new SelfSubscriptionNotAllowedException(); } diff --git a/services/subscribe/src/main/resources/application-prod.yml b/services/subscribe/src/main/resources/application-prod.yml index ef520ab4..680dc692 100644 --- a/services/subscribe/src/main/resources/application-prod.yml +++ b/services/subscribe/src/main/resources/application-prod.yml @@ -50,3 +50,19 @@ security: inbox: max-event-age-minutes: 60 + +resilience4j: + circuitbreaker: + instances: + creatorService: + register-health-indicator: true + sliding-window-type: COUNT_BASED + sliding-window-size: 20 + minimum-number-of-calls: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 3 + timelimiter: + instances: + creatorService: + timeout-duration: 2s diff --git a/services/waiting/src/main/java/kr/magicbox/waiting/adapter/out/communication/grpc/ReleaseGrpcAdapter.java b/services/waiting/src/main/java/kr/magicbox/waiting/adapter/out/communication/grpc/ReleaseGrpcAdapter.java new file mode 100644 index 00000000..8e21ed5a --- /dev/null +++ b/services/waiting/src/main/java/kr/magicbox/waiting/adapter/out/communication/grpc/ReleaseGrpcAdapter.java @@ -0,0 +1,72 @@ +package kr.magicbox.waiting.adapter.out.communication.grpc; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import kr.magicbox.waiting.adapter.out.communication.ServiceHost; +import kr.magicbox.waiting.adapter.out.communication.grpc.exception.ReleaseServiceUnavailableException; +import kr.magicbox.waiting.application.port.out.ReleaseQueryPort; +import kr.magicbox.waiting.domain.vo.ReleaseId; +import kr.magicbox.waiting.grpc.release.GetRemainingQuantityRequest; +import kr.magicbox.waiting.grpc.release.GetRemainingQuantityResponse; +import kr.magicbox.waiting.grpc.release.IsReleaseOnSaleRequest; +import kr.magicbox.waiting.grpc.release.IsReleaseOnSaleResponse; +import kr.magicbox.waiting.grpc.release.ReleaseServiceGrpc; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.grpc.client.GrpcChannelFactory; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +@Component +@RequiredArgsConstructor +@Slf4j +public class ReleaseGrpcAdapter implements ReleaseQueryPort { + + private final GrpcChannelFactory grpcChannelFactory; + + @Override + @CircuitBreaker(name = "releaseService", fallbackMethod = "isOnSaleFallback") + public Mono isOnSale(ReleaseId releaseId) { + return Mono.fromCallable(() -> { + IsReleaseOnSaleRequest request = IsReleaseOnSaleRequest.newBuilder() + .setReleaseId(releaseId.value()) + .build(); + + ReleaseServiceGrpc.ReleaseServiceFutureStub stub = + ReleaseServiceGrpc.newFutureStub(grpcChannelFactory.createChannel(ServiceHost.RELEASE.getHostName())); + ListenableFuture future = stub.isReleaseOnSale(request); + IsReleaseOnSaleResponse response = Futures.getUnchecked(future); + + return response.getOnSale(); + }).subscribeOn(Schedulers.boundedElastic()); + } + + @Override + @CircuitBreaker(name = "releaseService", fallbackMethod = "getRemainingQuantityFallback") + public Mono getRemainingQuantity(ReleaseId releaseId) { + return Mono.fromCallable(() -> { + GetRemainingQuantityRequest request = GetRemainingQuantityRequest.newBuilder() + .setReleaseId(releaseId.value()) + .build(); + + ReleaseServiceGrpc.ReleaseServiceFutureStub stub = + ReleaseServiceGrpc.newFutureStub(grpcChannelFactory.createChannel(ServiceHost.RELEASE.getHostName())); + ListenableFuture future = stub.getRemainingQuantity(request); + GetRemainingQuantityResponse response = Futures.getUnchecked(future); + + return response.getRemainingQuantity(); + }).subscribeOn(Schedulers.boundedElastic()); + } + + @SuppressWarnings("unused") + private Mono isOnSaleFallback(ReleaseId releaseId, Throwable throwable) { + throw new ReleaseServiceUnavailableException(throwable); + } + + @SuppressWarnings("unused") + private Mono getRemainingQuantityFallback(ReleaseId releaseId, Throwable throwable) { + throw new ReleaseServiceUnavailableException(throwable); + } +} diff --git a/services/waiting/src/main/resources/application-dev.yml b/services/waiting/src/main/resources/application-dev.yml new file mode 100644 index 00000000..a06c0fc9 --- /dev/null +++ b/services/waiting/src/main/resources/application-dev.yml @@ -0,0 +1,49 @@ +spring: + application: + name: waiting-dev + jackson: + property-naming-strategy: SNAKE_CASE + grpc: + server: + port: ${GRPC_SERVER_PORT} + client: + channels: + release-service: + address: ${RELEASE_SERVICE_URL} + negotiation-type: plaintext + keep-alive-time: 30s + keep-alive-timeout: 5s + kafka: + bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS} + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.apache.kafka.common.serialization.StringSerializer + consumer: + auto-offset-reset: earliest + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + value-deserializer: org.apache.kafka.common.serialization.StringDeserializer + data: + redis: + host: ${REDIS_HOST} + port: ${REDIS_PORT} + +security: + trusted: + ips: + - ${TRUSTED_IP_GATEWAY} + +resilience4j: + circuitbreaker: + instances: + releaseService: + register-health-indicator: true + sliding-window-type: COUNT_BASED + sliding-window-size: 20 + minimum-number-of-calls: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 3 + timelimiter: + instances: + releaseService: + timeout-duration: 2s diff --git a/services/waiting/src/main/resources/application-local.yml b/services/waiting/src/main/resources/application-local.yml index 88959f7b..85767165 100644 --- a/services/waiting/src/main/resources/application-local.yml +++ b/services/waiting/src/main/resources/application-local.yml @@ -30,6 +30,22 @@ spring: keep-alive-time: 30s keep-alive-timeout: 5s +resilience4j: + circuitbreaker: + instances: + releaseService: + register-health-indicator: true + sliding-window-type: COUNT_BASED + sliding-window-size: 20 + minimum-number-of-calls: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 10s + permitted-number-of-calls-in-half-open-state: 3 + timelimiter: + instances: + releaseService: + timeout-duration: 2s + server: port: ${SERVER_PORT} diff --git a/services/waiting/src/main/resources/application-prod.yml b/services/waiting/src/main/resources/application-prod.yml new file mode 100644 index 00000000..dbe7c48f --- /dev/null +++ b/services/waiting/src/main/resources/application-prod.yml @@ -0,0 +1,47 @@ +spring: + application: + name: waiting-prod + jackson: + property-naming-strategy: SNAKE_CASE + grpc: + client: + channels: + release-service: + address: ${RELEASE_SERVICE_URL} + negotiation-type: plaintext + keep-alive-time: 30s + keep-alive-timeout: 5s + kafka: + bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS} + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.apache.kafka.common.serialization.StringSerializer + consumer: + auto-offset-reset: earliest + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + value-deserializer: org.apache.kafka.common.serialization.StringDeserializer + data: + redis: + host: ${REDIS_HOST} + port: ${REDIS_PORT} + +security: + trusted: + ips: + - ${TRUSTED_IP_GATEWAY} + +resilience4j: + circuitbreaker: + instances: + releaseService: + register-health-indicator: true + sliding-window-type: COUNT_BASED + sliding-window-size: 20 + minimum-number-of-calls: 10 + failure-rate-threshold: 50 + wait-duration-in-open-state: 30s + permitted-number-of-calls-in-half-open-state: 5 + timelimiter: + instances: + releaseService: + timeout-duration: 2s