[Slack] Slack daily bot을 만들어보자 (2)
들어가며
node.js와 slack client를 이용해 slack의 bot을 만들어보자.
Node.js와 slack client 사용법에 대해서는 Slack bot 만들기 (1) 을 참고 한다.
기존에 slack bot을 만들려고 할 때 message 이벤트를 이용해서 저장하려고 하였는데
해당 방식 보다 특정 시간에 메시지를 크롤링하여 저장하는 방식이 간단하고 다른 이벤트를 처리할 필요 없어 해당 방식으로 변경한다.
Work flow
- daily bot은 특정 시간에 메시지를 발송한다.
- daily bot이 작성한 메시지에 thread를 이용해 댓글 방식으로 자신의 daily를 작성한다.
- daily bot은 특정 시간에 daily message에 작성된 thread 댓글을 크롤링 하여 저장한다.
1. 특정 시간에 메시지 발송
node.js에서는 node-cron이라는 라이브러리가 있어 해당 cron 방식을 이용하기로 했다.
$ npm install --save node-cron
해당 라이브러리의 가장 좋은 점은 아래 2가지 이다.
- 월~금으로만 설정 가능
- timezone으로 설정 가능
휴일에 대해서는 어쩔 수 없지만 주말을 제외하고 알아서 글을 작성 및 저장해 줄 수 있는 옵션과 서버 시간이 한국시간이 아닌 경우 엉뚱한 시간으로 동작할 수 있어 타임존을 셋팅할 수 있는 부분이 마음에 들었다.
daily bot은 YYYY-MM-DD 포맷으로 메시지를 작성하며 해당 메시지에 id(YYYY-MM-DD), channel, ts에 대해서 저장한다.
- channel과 ts를 저장하는 이유는 해당 channel에 ts를 통해서 thread 내용을 크롤링 할 수 있기 때문에 저장한다.
- YYYY-MM-DD는 해당 일에 대해서 데이터 크롤링 id로 사용하기 위해 저장한다.
cron.schedule('0 0 9 * * 1-5', () => {
(async () => {
try {
const rtmCallResult = await SlackClient.sendMessage(`${DateUtils.getTodayDateFormat()} daily`, channel);
const newVar = await BotTask.createOne({
id: DateUtils.getTodayDateFormat(),
channel,
ts: rtmCallResult.ts,
temp: JSON.stringify(rtmCallResult)
});
} catch (e) {
console.error(e);
}
})();
}, {
timezone
});
- 해당 채널에 원하는 메시지 포맷으로 전송한다.
- 전송 후 id, channel, ts를 저장해 둔다.
추후 id를 통해서 해당 날의 daily thread를 저장하는 용도로 쓰이기 위해서 저장 해둔다.
2. 메시지 thread 크롤링
slack에서는 conversations.replies를 통해서 해당 thread에 작성된 메시지를 크롤링 할 수 있다.
크롤링을 하기 위해서는 token, channel, ts가 required기 때문에 앞에서 channel, ts를 저장했으며 token은 slack bok에 token을 이용하면 된다.
cron.schedule('0 0 19 * * 1-5', () => {
(async () => {
try {
const botTask = await BotTask.findByPk(DateUtils.getTodayDateFormat());
const ts = botTask.ts;
const channel = botTask.channel;
const date = botTask.id;
const tasks = await SlackClient.conversionReplies({ts, channel});
const {messages} = tasks;
for (const task of messages) {
if (task.bot_id) {
continue;
}
const username = await SlackApi.getUsername(task.user);
const taskInfo = {
id: `${channel}-${task.ts}`,
username,
date: date,
task: task.text
};
const saved = await Task.createOne(taskInfo);
}
} catch (error) {
console.error(error);
}
})();
}, {
timezone
});
- id를 통해서 해당 날의 daily 메시지 데이터를 조회한다. (YYYY-MM-DD 사용)
- channel, ts에 정보를 바탕으로 thread에 replies를 조회 한다.
- 해당 데이터 가공한 뒤 데이터를 저장한다.
마치며
처음에 message 이벤트를 처리하여 해결하려고 하니, message의 changed 이벤트와 message 이벤트의 response 포맷이 달라 매 번 업데이트를 해야 하나 고민했었는데 해당 방식처럼 크롤링으로 변경하니 사용자들이 업데이트를 하던지 안하던지 상관없이 최종 작성된 text로 데이터가 나와 이벤트 처리에 대한 고민을 해결할 수 있었다.
데이터 모델 관련해서는 sequelize
를 사용하였는데 ORM을 제공해주고 db table도 없으면 생성해줘서
별 다른 셋팅을 하지 않아도 되서 편했었다.
생각보다 사용법도 간단하여 다음에 포스팅을 할 예정이다.
Leave a comment