직장에 있을 때 가장 고민을 많이 했던 시간은 역시 점심 먹을 때다. 매번 똑같은 회사생활에서 점심은 색다른 이벤트이며, 점심을 잘 먹였느냐에 따라서 오후 컨디션이 결정될 때가 있다. 여튼 점심을 먹기 위해 고민하는 시간이 길어질수록 점심시간은 짧아졌기에, 이런 현상을 어느정도 줄여줄 수 있는 점심 추천기를 만들어 보기로 했다.
목표
- 슬랙과 연동하여 점심시간 10분전에 추천을 받았으면 좋겠다.
- 식당 추가 및 삭제 가능
- 혹시 모르니 즉시 추천 가능
해당 조건들을 가지고 점심을 추천할 수 있는(사내 직원들만 이용 가능한) 간단한 서비스를 만들어 보기로 했다.
구상
먼저 비용이 적게 들고 빨리 제작할 수 있어야 한다. 이것은 예전에 만들었던 람다를 사용해서 만들어 보기로 했다.
하지만 람다를 사용하게 되면 함수를 콜드 스타트로 호출할 때 마다 로컬에 있는 정보가 사라지게 된다. 이를 해결하기 위해서 온디맨드 다이나모DB와 연동하여 데이터를 게속 저장할 수 있게 하면서도 비용도 매우 적게 들게 하였다.
그외 다양한 서버리스 프레임워크의 사용법과 배포 방법은 아래 사이트에서 자세하게 나와있다.
https://tre2man.tistory.com/299
다이나모 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
크론작업
https://www.serverless.com/examples/aws-node-scheduled-cron
전체코드
https://github.com/tre2man/lunch-recommend
'메이킹 > 메이킹 프로젝트' 카테고리의 다른 글
통관번호 조회 어플 제작기 (2) | 2023.05.08 |
---|---|
카카오톡 학식봇 AWS Lambda로 전환하기 (0) | 2022.09.12 |
아두이노 프로를 사용한 스탠드 작동부 제작 (0) | 2020.04.21 |
원격 컨트롤 및 알람 기능이 있는 스위치 제작 - 1 (0) | 2020.04.07 |
서보모터를 이용한 간단한 로봇 팔 제작기 (0) | 2020.03.04 |