메이킹/메이킹 프로젝트

슬랙 점심 추천기 만들기

트리맨스 2022. 11. 14. 16:02
반응형


직장에 있을 때 가장 고민을 많이 했던 시간은 역시 점심 먹을 때다. 매번 똑같은 회사생활에서 점심은 색다른 이벤트이며, 점심을 잘 먹였느냐에 따라서 오후 컨디션이 결정될 때가 있다. 여튼 점심을 먹기 위해 고민하는 시간이 길어질수록 점심시간은 짧아졌기에, 이런 현상을 어느정도 줄여줄 수 있는 점심 추천기를 만들어 보기로 했다.

 

목표


  1. 슬랙과 연동하여 점심시간 10분전에 추천을 받았으면 좋겠다.
  2. 식당 추가 및 삭제 가능
  3. 혹시 모르니 즉시 추천 가능

해당 조건들을 가지고 점심을 추천할 수 있는(사내 직원들만 이용 가능한) 간단한 서비스를 만들어 보기로 했다.

 

구상


먼저 비용이 적게 들고 빨리 제작할 수 있어야 한다. 이것은 예전에 만들었던 람다를 사용해서 만들어 보기로 했다.
하지만 람다를 사용하게 되면 함수를 콜드 스타트로 호출할 때 마다 로컬에 있는 정보가 사라지게 된다. 이를 해결하기 위해서 온디맨드 다이나모DB와 연동하여 데이터를 게속 저장할 수 있게 하면서도 비용도 매우 적게 들게 하였다.
그외 다양한 서버리스 프레임워크의 사용법과 배포 방법은 아래 사이트에서 자세하게 나와있다.
https://tre2man.tistory.com/299

 

Typescript를 이용한 어플리케이션 Lambda에 배포하기

요즘 lambda가 재밌어 보여서 계속 알아보는 중이다. 람다 (서버리스) 애플리케이션에 대한 설명은 다음 사이트에 잘 나와있다. https://www.redhat.com/ko/topics/cloud-native-apps/what-is-serverless 서버리스란?

tre2man.tistory.com

 

 

다이나모 DB 연동


AWS는 nodejs용 라이브러리를 제공하고 있다. AWS 계정의 키 파일을 만든 후, 간단한 세팅을 통해서 dynamoDB와 연동하자.
먼저 AWS 콘솔에서 다이나모 DB를 제작한다. 이 때 생성하려는 다이나모DB는 온디맨드 모드로 제작하면 비용이 거의 나오지 않는다.

이후 NodeJS 환경에서 다음과 같이 코드를 작성하면 AWS의 설정 및 다이나모DB 객체를 불러올 수 있다.

import AWS, { Credentials } from "aws-sdk";

AWS.config.update({
  region: "ap-northeast-2",
  credentials: new Credentials({
    accessKeyId: process.env.MY_AWS_ACCESS_KEY_ID as string,
    secretAccessKey: process.env.MY_AWS_SECRET_ACCESS_KEY as string,
  }),
});

const dynamo = new AWS.DynamoDB.DocumentClient();


가장 최신 버전에서는 credential에 들어가는 원소가 객체였다. 도큐먼트에도 나오지 않았다. 항상 타입을 잘 확인하고 사용을 해야 할 것 같다.

다이나모DB는 NoSQL기반의 DB이고, 서버리스 기반이다. 그래서 key-value값으로 이루어진 거대한 JSON파일이라고 생각하면 편하다. 테이블을 제작할 때 칼럼을 미리 만들어 두지 않아도 알아서 잘 검색하니, 바로 쓰면 된다. 예시로 데이터를 조회하는 코드만 하나 예시로 올려 둔다. 나머지 작업에 대해서는 공식 문서에 자세히 적혀 있었다.

/**
 * 데이터 조회
 * @param name 탐색할 key
 */
export const readData = async (name?: string): Promise<MenuInfo[]> => {
  try {
    if (!!name) {
      return new Promise((resolve) => {
        dynamo.get(
          {
            TableName: "lunch-list",
            Key: {
              name,
            },
          },
          (err, data) => {
            if (!!data.Item) {
              resolve([data.Item] as MenuInfo[]);
            }
            resolve([]);
          }
        );
      });
    } else {
      return new Promise((resolve) => {
        dynamo.scan(
          {
            TableName: "lunch-list",
          },
          (err, data) => {
            resolve(data.Items as MenuInfo[]);
          }
        );
      });
    }
  } catch (e) {
    return [];
  }
};

 

 

크론 동작


현재 프로그램은 서버리스 프레임워크를 기반으로 제작하고, 배포 환경도 람다인지라 자체적인 크론 트리거를 제작하여 배포할 수 있다. 해당 동작은 serverless.yml안에 있으며, 트리거의 timezone은 서울로 해야지 한국 지역에서 cron작업이 제시간에 잘 동작했다.
아래에 있는 코드는 월~금 11:50시 마다 크론 동작을 수행한다. 점심 10분전에 밥을 추천하는 로직을 실행한다.

service: lunch-recommendation

frameworkVersion: "3"

plugins:
  - serverless-plugin-typescript
  - serverless-offline
  - serverless-local-schedule
useDotenv: true

provider:
  name: aws
  runtime: nodejs16.x
  region: ap-northeast-2
  environment:
    MY_AWS_ACCESS_KEY_ID: ${env:AWS_ACCESS_KEY_ID}
    MY_AWS_SECRET_ACCESS_KEY: ${env:AWS_SECRET_ACCESS_KEY}

functions:
  recommend-cron:
    handler: src/recommend-cron.main
    events:
      - schedule: 
          rate : cron(50 11 ? * TUE-SAT *)
          timezone: Asia/Seoul


serverless 기반의 서버를 다 작성했으면, 여러 config값들을 설정한 다음 serverless offline 명령어로 배포를 시작한다. 이 때 생성되는 API 주소는 다음에 나올 슬랙과 연동할 때 필요한 주소다. 나중에 API Gateway에 가도 볼 수 있다.

 

슬랙과 연동


슬랙에는 '슬래시 커맨드' 라는 기능이 있다. 슬랙 채널에서 '/' + '메시지' + '옵션' 을 대화창에 날리면, 메시지가 특정한 명령어로 인식되어 동작을 수행한다. 이러한 기능을 통해서 메뉴 추가/삭제/추천 기능을 만들어 보려고 한다.

생성된 앱의 설정에서 Slash Commands 메뉴를 선택한다. 이후 원하는 커맨드와 API 주소를 매칭하여 추가한다. 자세한 내용은 글의 하단에 있는 공식 문서에 자세히 나와 있다.

 

 

자동배포


배포까지 자동으로 하면 좋겠다는 생각이 들어서, github action을 통해서 간단히 배포하기로 했다. 배포 환경은 node 16.x 버전의 인스턴스를 기반으로 했고, 서버리스를 설치한 뒤 배포를 실행했다. aws 관련 보안키 파일만 secrets에 지정하면 바로 배포가 되었다.

name: deploy kakaobob

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [16.x]
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"
      - name: Install dependencies
        run: npm ci
      - name: Install serverless
        run: npm install -g serverless
      - name: Deploy
        run: npm run deploy:ci

 

결과 확인


최종적으로 잘 동작하는 모습을 알 수 있다!

전체 코드는 아래 링크되어 있다.

 

참고자료


슬래시 커맨드
https://api.slack.com/interactivity/slash-commands#what_are_commands

 

Enabling interactivity with Slash Commands | Slack

What are Slash Commands? Slash Commands allow users to invoke your app by typing a string into the message composer box. A submitted Slash Command will cause a payload of data to be sent from Slack to the associated app. The app can then respond in whateve

api.slack.com

크론작업
https://www.serverless.com/examples/aws-node-scheduled-cron

 

AWS Node Scheduled Cron example in NodeJS

This is an example of creating a function that runs as a cron job using the serverless 'schedule' event.

www.serverless.com

전체코드
https://github.com/tre2man/lunch-recommend

 

GitHub - tre2man/lunch-recommend: 슬랙 점심 추천기

슬랙 점심 추천기. Contribute to tre2man/lunch-recommend development by creating an account on GitHub.

github.com

 

반응형