물류 서비스 변경 이슈 대응

ahn__jh·2022년 9월 16일
0

개요

스프린트 도중 운영 팀에서 재고가 맞지 않아요... 라는 슬랙을 받게 되었다🤯

베트남측 물류 서비스가 변경된다 라고 듣긴 했으나 베트남에서 물류관리 서비스를 계도기 없이 다른 서비스로 바로 전환하게 되어 해당 이슈가 발생하게 되었다.

전환한 서비스에서 API를 제공하기로 하였지만 너무 급작 스럽게 전환하게 되어 API도 준비 되어 있지 않았으며, 당장 재고현황을 제공해야 하는 이슈를 처리하면서 글을 작성합니다.

개발 아키텍쳐

코어팀에서 전환한 서비스를 일정시간 마다 크롤링하여 재고 정보를 파트너센터 S3에 업로드 하고 S3트리거를 통해 업로드시 자동으로 람다함수를 호출하여 엑셀 컬럼을 검증하고 파트너센터DB 재고 테이블에 upsert하는 방식으로 구성하였다.

그리고 추가로 기존 방식이였던 재고정보가 창고별 지역별로 분리 되어있지 않아 추후에 지역별, 창고별 재고정보를 요청 했을 때 대응할수 있도록 데이터 적재 방법을 하노이,호치민 창고별 입고, 출고 내역을 따로 관리 하는 방법으로 개선하였다.

🐶🦶🏻

serverless 프레임워크를 이용
서버리스에서 지원하는 s3에 trigger를 걸수있도록 공식문서에서 안내 하고있다.
공식문서 : https://www.serverless.com/framework/docs/providers/aws/events/s3

//serverless handler를 작성
export const stock: Handler = async (event): Promise<void> => {
  
  //s3트리거가 작동하면 event를 통해 업로드된 파일의 키와 버켓정보를 가져올수있다.
  const bucket = event.Records[0].s3.bucket.name as string;
  const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
  const params = {
    Bucket: bucket,
    Key: key,
  };
  try {
    //키를 통해 가져온 excel파일을 가져옵니다.
    const file = await s3.getObject(params);
    const fileToBuffer = await streamToBuffer(file.createReadStream());

    const { stockDatas, stockLogDatas, warehouse } = await getStockSummaryExcelData(fileToBuffer, key);

    if (stockDatas.length === 0 || stockLogDatas.length === 0) {
      await sendAlarm(`[재고 업로드 시스템] ${process.env.NODE_ENV} ${key} STOCK 업로드할 데이터가 없습니다.`);
      return;
    }
	
    //읽어온 excel파일을 가공되어 만들어진 데이터를 파트너센터 DB에 적재
    await Promise.all([insert(stockLogInsertRawQuery, stockLogDatas), insert(stockInsertRawQuery, stockDatas)]);

    await sendAlarm(`[재고 업로드 시스템] ${process.env.NODE_ENV} ${warehouse} STOCK 업로드 완료`);
  } catch (error) {
    await sendAlarm(`[재고 업로드 시스템] ${process.env.NODE_ENV} STOCK 업로드 실패 ERROR: ${error}`);
  }
};
//엑셀 파일을 읽어서 DB에 업로드 할수 있도록 가공하는 로직
export const getStockSummaryExcelData = async (
  file: Buffer,
  key: string,
): Promise<{
  stockLogDatas: [string, string, number, number, number, number, StockTypeEnum, Date, WarehouseEnum, LocationEnum][];
  stockDatas: [string, string, number, WarehouseEnum, LocationEnum][];
  warehouse: WarehouseEnum;
}> => {
  const workbook = xlsx.read(file.buffer, {
    type: 'buffer',
    cellDates: true,
    cellText: false,
    cellHTML: false,
  });
  const worksheet = workbook.Sheets['Sheet'];
  if (!worksheet) {
    throw new Error(`[${process.env.NODE_ENV}] 엑셀 재고 데이터 sheet를 확인할 수 없습니다.`);
  }

  //key에서 "|" 구분자로 위치, 창고, 날짜를 구분
  const [location, warehouse, date] = key.split('|');

  const parseLocation = location.slice(location.indexOf('/') + 1) as LocationEnum;
  const parseWarehouse = warehouse.toUpperCase().replace(/ /g, '_') as WarehouseEnum;
  const orderedAt = new Date(date);

  if (!Object.keys(WarehouseEnum).includes(parseWarehouse)) {
    throw new Error(`[${process.env.NODE_ENV}] 존재하지 않는 창고 입니다.`);
  }

  const range = xlsx.utils.decode_range(worksheet['!ref'] as string);
  //컬럼 검증 및 데이터를 읽어 오는 로직 (엑셀의 양식이 변경될 수 있기때문에 validation 추가)
  const rows = getExcelDataWithHeaderValidationLogic(range, worksheet);

  //가져온 데이터를 DB에 적재 하기위해 가공하는 로직
  const { stockDatas, stockLogDatas } = transFormExcelData(rows, orderedAt, parseWarehouse, parseLocation);

  return {
    stockLogDatas,
    stockDatas,
    warehouse: parseWarehouse,
  };
};

엑셀파일을 가져와서 가공하는 로직이 완료 되었고 이제 람다 함수를 생성하는 serverless.yml 파일을 작성합니다.

service: kr-partner-center-batch
frameworkVersion: '2'

plugins:
  - serverless-plugin-typescript
  - serverless-offline
  - serverless-dotenv-plugin
useDotenv: true

provider:
  ---aws 환경---

functions:
  # 재고 입,출고 업로드
  stock:
    name: kr-partner-center-batch-${opt:stage, 'dev'}
    timeout: 30
    handler: "./src/handlers/stock/handler.stock"
    events:
      #서버리스 s3 이벤트 트리거 공식문서 https://www.serverless.com/framework/docs/providers/aws/events/s3
      - s3:
	      //partner-center 버켓에 생성된 cloudify 폴더의 .xlsx파일명으로 생성된 파일의 이벤트를 생성
          bucket: partner-center 
          event: s3:ObjectCreated:*
          rules:
            - prefix: cloudify/
            - suffix: .xlsx
          existing: true

yml파일을 작성하고 배포하면 개발 끄읏!

블로커 처리

1. 서버리스 3 버전에서 s3트리거 event를 통해 호출하는 람다를 배포할 수 없었다.

  • 이유는 모르겠다. 찾다보니 2버전 으로 가능하단 공식문서를 본 것 같은데 우선 2버전으로 변경하여 해결하고 이후에 찾아 보기로하여 해결

2. 개발서버 DB에 적재 테스트를 하기위해 dev로 배포를 하고 테스트 완료 후 운영DB에 적재하는 lambda를 배포 하려했지만 에러가 발생했다.

  • 한개의 s3에는 한개의 lambda event trigger 밖에 작동하지 않는다 두가지 배포하니 배포도중 에러가 발생하여 개발 lambda는 삭제했다.

3. 개발중에 수차례 엑셀 양식이 변경됨

  • 이 부분은 물류 서비스측에서 계속 변경되어 근본적인 문제를 해결할수 없기에 API가 개발되어 공유되기 전까진 빠르게 대응하기로 하여 엑셀의 컬럼과 순서를 확인하는 validation을 추가

0개의 댓글