240808 TIL

송형근·2024년 8월 8일
0

TIL

목록 보기
9/43
post-thumbnail

스파르타 Java 단기 심화 과정


코드카타


프로그래머스 42840 모의고사

https://school.programmers.co.kr/learn/courses/30/lessons/42840

— 문제 설명

수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.

1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...

1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.

— 제한 조건

  • 시험은 최대 10,000 문제로 구성되어있습니다.
  • 문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
  • 가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.

— 입출력 예

answersreturn
[1,2,3,4,5][1]
[1,3,2,4,2][1,2,3]

입출력 예 #1

  • 수포자 1은 모든 문제를 맞혔습니다.
  • 수포자 2는 모든 문제를 틀렸습니다.
  • 수포자 3은 모든 문제를 틀렸습니다.

따라서 가장 문제를 많이 맞힌 사람은 수포자 1입니다.

입출력 예 #2

  • 모든 사람이 2문제씩을 맞췄습니다.

— 문제 풀이

import java.util.*;

class Solution {
    /*
    수포자 1 : 1 2 3 4 5 ...
    수포자 2 : 2 1 2 3 2 4 2 5 ...
    수포자 3 : 3 3 1 1 2 2 4 4 5 5 ...
    */
    public int[] solution(int[] answers) {
        int[] method1 = {1,2,3,4,5};
        int[] method2 = {2,1,2,3,2,4,2,5};
        int[] method3 = {3,3,1,1,2,2,4,4,5,5};
        
        int[] cnt = new int[3+1]; // 수포자 3명 맞춘 갯수 cnt
        int best = 0;
        for(int i=0;i<answers.length;i++){
            for(int j=1;j<=3;j++){
                if(j==1 && answers[i] == method1[i%5]){
                    cnt[j]++;
                }else if (j==2 && answers[i] == method2[i%8]){
                    cnt[j]++;
                }else if (j==3 && answers[i] == method3[i%10]){
                    cnt[j]++;
                }
                if(best<cnt[j]) best++;
            }
        }
        
        ArrayList<Integer>list = new ArrayList<>();
        for(int i=1;i<=3;i++){
            if(best==cnt[i]) list.add(i);
        }
        int[] answer = new int[list.size()];
        for(int i=0;i<answer.length;i++){
            answer[i] = list.get(i);
        }
        return answer;
    }
}

프로그래머스 12977 소수 만들기

https://school.programmers.co.kr/learn/courses/30/lessons/12977

— 문제 설명

주어진 숫자 중 3개의 수를 더했을 때 소수가 되는 경우의 개수를 구하려고 합니다. 숫자들이 들어있는 배열 nums가 매개변수로 주어질 때, nums에 있는 숫자들 중 서로 다른 3개를 골라 더했을 때 소수가 되는 경우의 개수를 return 하도록 solution 함수를 완성해주세요.

— 제한 조건

  • nums에 들어있는 숫자의 개수는 3개 이상 50개 이하입니다.
  • nums의 각 원소는 1 이상 1,000 이하의 자연수이며, 중복된 숫자가 들어있지 않습니다.

— 입출력 예

numsresult
[1,2,3,4]1
[1,2,7,6,4]4

입출력 예 #1
[1,2,4]를 이용해서 7을 만들 수 있습니다.

입출력 예 #2
[1,2,4]를 이용해서 7을 만들 수 있습니다.
[1,4,6]을 이용해서 11을 만들 수 있습니다.
[2,4,7]을 이용해서 13을 만들 수 있습니다.
[4,6,7]을 이용해서 17을 만들 수 있습니다.

— 문제 풀이

class Solution {
    public int cnt = 0;
    public int solution(int[] nums) {

        cal(nums,0,0,0);

        return cnt;
    }
    public void cal(int[] nums, int cur, int pick, int sum){
        if(pick == 3){
            if(isPrime(sum))cnt++;
        }else{
            for(int i=cur;i<nums.length;i++){
                cal(nums, i+1, pick+1, sum+nums[i]);
            }
        }
    }
    
    public boolean isPrime(int n){
        if(n==0 || n==1) return false;
        for(int i=2;i<=Math.sqrt(n);i++){
            if(n%i==0) return false;
        }
        return true;
    }
}

MSA 실습 프로젝트

Order Entity - OrderProduct Entity 연관관계 수정

  • 기존
    • Order Entity에서 ElementCollection 활용
          @ElementCollection
          @CollectionTable(name = "order_items", joinColumns = @JoinColumn(name = "order_id"))
          @Column(name = "order_item_id")
          private List<Long> orderItemIds;
  • OneToMany - ManyToOne 로 변경
    • Order Entity
          @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
          private List<OrderProduct> orderProducts = new ArrayList<>();
    • OrderProduct Entity
          @ManyToOne
          @JoinColumn(name = "order_id")
          private Order order;
    • Order Entity 내 OrderProduct add 메서드 추가
          public void addOrderProducts(OrderProduct orderProduct){
              orderProducts.add(orderProduct);
              orderProduct.setOrder(this);
          } 
    • Update 메서드 수정
          public void updateOrder(String name, List<Long> orderProductIds, OrderStatus status, String userId) {
              this.name = name;
              this.orderProducts.clear();
              for(Long productId : orderProductIds){
                  this.addOrderProducts(OrderProduct.builder().productId(productId).build());
              }
              this.status = status;
              this.updatedBy = userId;
          }
  • https://github.com/lukeydokey/Sparta-MSA/commit/8f058ccf165bba3a4f7336a67837ee32ffdfe14b

상품 전체 조회 추가 및 상품 수량 조정 로직 변경

  • 상품 전체 조회 구현
        public List<ProductResDto> getAllProducts(){
            try{
                return productRepository.findAll()
                        .stream().filter(p -> p.getDeletedAt() == null).map(Product::toResDto).toList();
            }catch (Exception e){
                log.error(e.getMessage());
                throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Internal server error");
            }
        }
  • 상품 수량 조정 로직 변경
    • 변경 사유 : 주문이 삭제되거나 변경이 되면 수량도 조정이 필요
    • reduceQuantity → updateQuantity
          @Transactional
          public void updateQuantity(Long productId, Integer quantity, String userId) {
              Product product = productRepository.findById(productId)
                      .filter(p -> p.getDeletedAt() == null)
                      .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Product not found or has been deleted"));
      
              if(product.getQuantity() + quantity < 0){
                  throw new IllegalArgumentException("Not Enough Product");
              }
      
              product.updateProduct(product.getName(), product.getDescription(),
                      product.getPrice(), product.getQuantity() + quantity, userId);
          }
    • 변경된 로직 예시 ( 주문 취소 - 상품 수량 +1 )
          @Transactional
          public void deleteOrder(Long orderId, String userId) {
              Order order = orderRepository.findById(orderId)
                      .filter(o -> o.getDeletedAt() == null)
                      .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Order not found or has been deleted"));
      
              // 주문 취소 때문에 수량 다시 +1
              for(OrderProduct product : order.getOrderProducts()){
                  productClient.updateQuantity(product.getProductId(),1, userId);
              }
      
              order.setDeleted(userId);
          }
  • https://github.com/lukeydokey/Sparta-MSA/commit/0d21a065219d293c6c9ffb4854a022943e80adc6

분산추적 설정 추가

  • 의존성 추가
    implementation 'io.github.openfeign:feign-micrometer'
    implementation 'io.micrometer:micrometer-tracing-bridge-brave'
    implementation 'io.zipkin.reporter2:zipkin-reporter-brave'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
  • application.yml 내 zipkins 설정 추가
    management:
      zipkin:
        tracing:
          endpoint: "http://{zipkins host}:{port}/api/v2/spans"
      tracing:
        sampling:
          probability: 1.0

Caching 추가

  • 의존성
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
  • application.yml 내 redis 설정 추가
     spring:
      data:
        redis:
          host: localhost
          port: 6379
          password: "!@34"
  • CacheConfig ( order )
    @Configuration
    @EnableCaching
    public class CacheConfig {
    
        @Bean
        public RedisCacheManager cacheManager(
                RedisConnectionFactory connectionFactory
        ) {
            RedisCacheConfiguration config = RedisCacheConfiguration
                    .defaultCacheConfig()
                    .disableCachingNullValues()
                    .entryTtl(Duration.ofSeconds(60))
                    .computePrefixWith(CacheKeyPrefix.simple())
                    .serializeValuesWith(
                            RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json())
                    );
    
            return RedisCacheManager.builder(connectionFactory)
                    .cacheDefaults(config)
                    .build();
        }
    }
  • RedisConfig ( order )
    @Configuration
    public class RedisConfig {
    
        @Bean
        public RedisTemplate<String, ProductResDto> productRedisTemplate(
                RedisConnectionFactory redisConnectionFactory
        ){
            RedisTemplate<String, ProductResDto> template = new RedisTemplate<>();
            template.setConnectionFactory(redisConnectionFactory);
            template.setKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(RedisSerializer.json());
            return template;
        }
    }
    • Order에서 FeignClient로 updateQuantity 호출 후 Product 정보가 변경 되므로 Product 캐시 삭제 필요
    • 어노테이션으로는 해당 작업이 불가하므로 RedisTemplate 활용해서 일괄 삭제
  • OrderService
    @Service
    @RequiredArgsConstructor
    @Transactional(readOnly = true)
    public class OrderService {
    
        private final OrderRepository orderRepository;
        private final ProductClient productClient;
        private final RedisTemplate<String, ProductResDto> productRedisTemplate;
        private final String PRODUCT_CACHE_PREFIX = "productCache::";
    
        @CachePut(cacheNames = "orderCache", key = "#result.orderId")
        @CacheEvict(cacheNames = "allOrdersCache", allEntries = true)
        @Transactional
        public OrderResDto createOrder(OrderReqDto requestDto, String userId){
            for( Long productId : requestDto.getOrderProductIds()){
                ProductResDto product = productClient.getProductById(productId);
                if(product == null || product.getQuantity() < 1){
                    throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Product is sold out");
                }
            }
            // product 수량 변경 되었으므로 캐시 삭제
            for(Long productId : requestDto.getOrderProductIds()){
                productClient.updateQuantity(productId,-1, userId);
                productRedisTemplate.delete(PRODUCT_CACHE_PREFIX + productId);
            }
    
            Order order = requestDto.toEntity();
            for(Long productId : requestDto.getOrderProductIds()){
                order.addOrderProducts(OrderProduct.builder().productId(productId).build());
            }
            order.setCreated(userId);
            return orderRepository.save(order).toResDto();
        }
    
        @Cacheable(cacheNames = "orderCache", key = "args[0]")
        public OrderResDto getOrderById(Long orderId){
            Order order = orderRepository.findById(orderId)
                    .filter(o -> o.getDeletedAt() == null)
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Order not found or has been deleted"));
            return order.toResDto();
        }
    
        @CachePut(cacheNames = "orderCache", key = "args[0]")
        @Caching(
                evict = {
                        @CacheEvict(cacheNames = "allOrdersCache", allEntries = true),
                        @CacheEvict(cacheNames = "allProductsCache", allEntries = true)
                }
        )
        @Transactional
        public OrderResDto updateOrder(Long orderId, OrderReqDto requestDto, String userId) {
            Order order = orderRepository.findById(orderId)
                    .filter(o -> o.getDeletedAt() == null)
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Order not found or has been deleted"));
    
            Set<Long> productsIdSet = new HashSet<>(); // 수량이 변경된 product를 담을 Set
    
            // 주문 상품 리스트를 새로 업뎃 예정이기 때문에 수량 다시 +1
            for(OrderProduct product : order.getOrderProducts()){
                productClient.updateQuantity(product.getProductId(),1, userId);
                productsIdSet.add(product.getProductId());
            }
    
            // 업데이트 된 주문 상품 리스트 수량 -1
            for(Long productId : requestDto.getOrderProductIds()){
                productClient.updateQuantity(productId,-1, userId);
                productsIdSet.add(productId);
            }
    
            // product 수량 변경 되었으므로 캐시 삭제
            for(Long productId : productsIdSet){
                productRedisTemplate.delete(PRODUCT_CACHE_PREFIX + productId);
            }
    
            order.updateOrder(requestDto.getName(), requestDto.getOrderProductIds(), OrderStatus.valueOf(requestDto.getStatus()) ,userId);
            return order.toResDto();
        }
    
        @Caching(
                evict = {
                        @CacheEvict(cacheNames = "allOrdersCache", allEntries = true),
                        @CacheEvict(cacheNames = "orderCache", key = "args[0]")
                }
        )
        @Transactional
        public void deleteOrder(Long orderId, String userId) {
            Order order = orderRepository.findById(orderId)
                    .filter(o -> o.getDeletedAt() == null)
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Order not found or has been deleted"));
    
            // 주문 취소 때문에 수량 다시 +1
            // product 수량 변경 되었으므로 캐시 삭제
            for(OrderProduct product : order.getOrderProducts()){
                productClient.updateQuantity(product.getProductId(),1, userId);
                productRedisTemplate.delete(PRODUCT_CACHE_PREFIX + product.getProductId());
            }
    
            order.setDeleted(userId);
        }
    
    }
  • CacheConfig ( product )
    @Configuration
    @EnableCaching
    public class CacheConfig {
    
        @Bean
        public RedisCacheManager cacheManager(
                RedisConnectionFactory connectionFactory
        ) {
            RedisCacheConfiguration config = RedisCacheConfiguration
                    .defaultCacheConfig()
                    .disableCachingNullValues()
                    .entryTtl(Duration.ofSeconds(60))
                    .computePrefixWith(CacheKeyPrefix.simple())
                    .serializeValuesWith(
                            RedisSerializationContext.SerializationPair.fromSerializer(
                                    RedisSerializer.java()
                            )
                    );
    
            return RedisCacheManager.builder(connectionFactory)
                    .cacheDefaults(config)
                    .build();
        }
    }
  • ProductResDto 수정
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public class ProductResDto implements Serializable { // implements Serializable 추가
        private Long id;
        private String name;
        private String description;
        private Integer price;
        private Integer quantity;
    }
    • Product 전체 조회시 List를 반환하게 되므로 implements Serializable 추가 필요
  • ProductService
    @Service
    @RequiredArgsConstructor
    @Slf4j(topic = "Product Service")
    @Transactional(readOnly = true)
    public class ProductService {
    
        private final ProductRepository productRepository;
    
        @CachePut(cacheNames = "productCache", key = "#result.id")
        @CacheEvict(cacheNames = "allProductsCache", allEntries = true)
        @Transactional
        public ProductResDto createProduct(ProductReqDto requestDto, String userId) {
            Product product = requestDto.toEntity();
            product.setCreated(userId);
            return productRepository.save(product).toResDto();
        }
    
        @CachePut(cacheNames = "productCache", key = "args[0]")
        @CacheEvict(cacheNames = "allProductsCache", allEntries = true)
        @Transactional
        public ProductResDto updateProduct(Long productId,ProductReqDto requestDto, String userId) {
            Product product = productRepository.findById(productId)
                    .filter(p -> p.getDeletedAt() == null)
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Product not found or has been deleted"));
    
            product.updateProduct(requestDto.getName(), requestDto.getDescription(),
                    requestDto.getPrice(), requestDto.getQuantity(), userId);
            return product.toResDto();
        }
    
        @Caching(
            evict = {
                    @CacheEvict(cacheNames = "allProductsCache", allEntries = true),
                    @CacheEvict(cacheNames = "productCache", key = "args[0]")
            }
        )
        @Transactional
        public void deleteProduct(Long productId, String userId) {
            Product product = productRepository.findById(productId)
                    .filter(p -> p.getDeletedAt() == null)
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Product not found or has been deleted"));
            product.setDeleted(userId);
        }
    
        @Cacheable(cacheNames = "allProductsCache", key = "methodName")
        public List<ProductResDto> getAllProducts(){
            try{
                return productRepository.findAll()
                        .stream().filter(p -> p.getDeletedAt() == null).map(Product::toResDto).toList();
            }catch (Exception e){
                log.error(e.getMessage());
                throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Internal server error");
            }
        }
    
        @Cacheable(cacheNames = "productCache", key = "args[0]")
        public ProductResDto getProductById(Long productId){
            Product product = productRepository.findById(productId)
                    .filter(p -> p.getDeletedAt() == null)
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Product not found or has been deleted"));
            return product.toResDto();
        }
    
        @CachePut(cacheNames = "productCache", key = "#result.id")
        @CacheEvict(cacheNames = "allProductsCache", allEntries = true)
        @Transactional
        public ProductResDto updateQuantity(Long productId, Integer quantity, String userId) {
            Product product = productRepository.findById(productId)
                    .filter(p -> p.getDeletedAt() == null)
                    .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Product not found or has been deleted"));
    
            if(product.getQuantity() + quantity < 0){
                throw new IllegalArgumentException("Not Enough Product");
            }
    
            product.updateProduct(product.getName(), product.getDescription(),
                    product.getPrice(), product.getQuantity() + quantity, userId);
            return product.toResDto();
        }
    }

AWS ECS / ECR 배포

ECR 이미지 수동 푸시

  • ECR 생성
  • Local 환경에서 Image Build
  • AWS 계정 Access key 생성
  • aws cli 설치
  • cmd 실행
  • aws --version aws cli 설치 확인
  • aws configure aws cli 계정 설정
    • Access Key : 발급한 Access Key
    • Secret Access Key : 발급한 Secret Access Key
    • 나머지 비워놔도 상관없음 ( 서울 리전은 ap-northeast-2 )
  • aws sts get-caller-identity 설정 완료 시 UserId, Account, Arn 정보 확인 가능
  • aws ecr get-login-password --region {Region} | docker login --username AWS --password-stdin {AWS UserId}.dkr.ecr.{Region}.amazonaws.com 설정으로 ECR 사용 가능
  • 이미지 빌드
  • 이미지 태그
    # 예시
    docker tag {빌드 한 이미지}:{빌드한 이미지 태그} {ECR URL}:{이미지 태그}
  • 이미지 푸시
    # 예시
    docker push {ECR URL}:{이미지 태그}

ECS 생성 및 설정

  • ECS 생성 ( 기본 설정 )
  • 태스크 생성
    • ECR에 Push한 이미지 URI를 토대로 태스크 생성
  • 서비스 생성
    • 생성한 태스크 설정

Github Action 설정

  • Secret 설정
    • Setting - Secrets and Variables - Actions 에 Repository Secret 설정
      • AWS_ACCESS_KEY_ID
      • AWS_SECRET_ACCESS_KEY
      • AWS_REGION
      • DB_PW
      • NAVER_SECRET
  • workflow 작성
    # This workflow will build and push a new container image to Amazon ECR,
    # and then will deploy a new task definition to Amazon ECS, when there is a push to the "master" branch.
    #
    # To use this workflow, you will need to complete the following set-up steps:
    #
    # 1. Create an ECR repository to store your images.
    #    For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`.
    #    Replace the value of the `ECR_REPOSITORY` environment variable in the workflow below with your repository's name.
    #    Replace the value of the `AWS_REGION` environment variable in the workflow below with your repository's region.
    #
    # 2. Create an ECS task definition, an ECS cluster, and an ECS service.
    #    For example, follow the Getting Started guide on the ECS console:
    #      https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun
    #    Replace the value of the `ECS_SERVICE` environment variable in the workflow below with the name you set for the Amazon ECS service.
    #    Replace the value of the `ECS_CLUSTER` environment variable in the workflow below with the name you set for the cluster.
    #
    # 3. Store your ECS task definition as a JSON file in your repository.
    #    The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`.
    #    Replace the value of the `ECS_TASK_DEFINITION` environment variable in the workflow below with the path to the JSON file.
    #    Replace the value of the `CONTAINER_NAME` environment variable in the workflow below with the name of the container
    #    in the `containerDefinitions` section of the task definition.
    #
    # 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
    #    See the documentation for each action used below for the recommended IAM policies for this IAM user,
    #    and best practices on handling the access key credentials.
    
    name: Deploy to Amazon ECS
    
    on:
      push:
        branches: [ 'action-test' ]
    
    env:
      AWS_REGION: ap-northeast-2                   # set this to your preferred AWS region, e.g. us-west-1
      ECR_REPOSITORY: sparta-cicd-test-lucas           # set this to your Amazon ECR repository name
      ECS_CLUSTER: sparta-ecs-lucas                 # set this to your Amazon ECS cluster name
      ECS_SERVICE_NAME: sparta-ecs-service-lucas
      ECS_TASK_DEFINITION: task-definition.json # set this to the path to your Amazon ECS task definition
      # file, e.g. .aws/task-definition.json
      CONTAINER_NAME: myselectshop-lucas           # set this to the name of the container in the
      # containerDefinitions section of your task definition
    
    permissions:
      contents: read
    
    jobs:
      deploy:
        name: Deploy
        runs-on: ubuntu-latest
        environment: production
    
        steps:
          - name: Checkout
            uses: actions/checkout@v4
    
          - name: Configure AWS credentials
            uses: aws-actions/configure-aws-credentials@v1
            with:
              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
              aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
              aws-region: ${{ env.AWS_REGION }}
    
          - name: Login to Amazon ECR
            id: login-ecr
            uses: aws-actions/amazon-ecr-login@v1
    
          - name: Build, tag, and push image to Amazon ECR
            id: build-image
            env:
              ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
              IMAGE_TAG: ${{ github.sha }}
            run: |
              # Build a docker container and
              # push it to ECR so that it can
              # be deployed to ECS.
              docker build --build-arg DBPW=${{ secrets.DB_PW }} --build-arg NAVERSECRET=${{ secrets.NAVER_SECRET }} -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
              docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
              echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
    
          - name: Fill in the new image ID in the Amazon ECS task definition
            id: task-def
            uses: aws-actions/amazon-ecs-render-task-definition@v1
            with:
              task-definition: ${{ env.ECS_TASK_DEFINITION }}
              container-name: ${{ env.CONTAINER_NAME }}
              image: ${{ steps.build-image.outputs.image }}
    
          - name: Deploy Amazon ECS task definition
            uses: aws-actions/amazon-ecs-deploy-task-definition@v1
            with:
              task-definition: ${{ steps.task-def.outputs.task-definition }}
              service: ${{ env.ECS_SERVICE }}
              cluster: ${{ env.ECS_CLUSTER }}
              wait-for-service-stability: true

Github Action on push 동작 X 이슈


MSA 고민 포인트

💡 생각해낸 답이 맞는 지 모르겠어서... 지적은 늘 환영입니다.
  1. 고객 주문 시 예상치 못한 오류로 인해 상품 서비스에서 재고 차감 하였으나, 주문 서비스에서 에러가 발생해 주문이 정상적으로 완료되지 않았을 경우 어떻게 해야 할까?
  • 오류가 발생했을 때 재고를 다시 되돌리는 로직을 구현해야 한다
  1. 마이크로서비스 간의 통신에 대한 보안을 어떻게 보장 해야할까?
  • 각 서비스를 오픈하는 방식이 아닌 각 서비스는 방화벽을 막아둔 상태에서 게이트웨이를 통해 서비스들을 접근하게 하고 게이트웨이에서 인증 및 인가 처리를 하면서 보안을 강화하자
profile
기록을 남겨보자

0개의 댓글