|
1 |
| -import { executeQuery, makeExecuteQuery, pool } from '~/mysql'; |
| 1 | +import { executeQuery } from '~/mysql'; |
2 | 2 | import { publishMessage } from '../slack/slack.service';
|
| 3 | +import { handleReservationOverdueAndAssignReservationToNextWaitingUser } from '../reservations/reservations.service'; |
| 4 | +import { logger } from '~/logger'; |
3 | 5 |
|
4 |
| -const succeedReservation = async (reservation: { bookId: number; bookInfoId: number }) => { |
5 |
| - const conn = await pool.getConnection(); |
6 |
| - const transactionExecuteQuery = makeExecuteQuery(conn); |
| 6 | +const sendSlackMessage = async (slack: string, message: string) => { |
7 | 7 | try {
|
8 |
| - const candidates: { |
9 |
| - id: number; |
10 |
| - slack: string; |
11 |
| - title: string; |
12 |
| - }[] = await transactionExecuteQuery( |
13 |
| - ` |
14 |
| - SELECT |
15 |
| - reservation.id AS id, |
16 |
| - user.slack AS slack, |
17 |
| - book_info.title AS title |
18 |
| - FROM |
19 |
| - reservation |
20 |
| - LEFT JOIN user ON |
21 |
| - user.id = reservation.userId |
22 |
| - LEFT JOIN book_info ON |
23 |
| - book_info.id = reservation.bookInfoId |
24 |
| - WHERE |
25 |
| - reservation.status = 0 AND |
26 |
| - reservation.bookInfoId = ? |
27 |
| - ORDER BY |
28 |
| - reservation.createdAt DESC |
29 |
| - LIMIT 1 |
30 |
| - `, |
31 |
| - [reservation.bookInfoId], |
32 |
| - ); |
33 |
| - if (candidates.length !== 0) { |
34 |
| - await transactionExecuteQuery( |
35 |
| - ` |
36 |
| - UPDATE |
37 |
| - reservation |
38 |
| - SET |
39 |
| - bookId = ?, |
40 |
| - endAt = DATE_ADD(NOW(), INTERVAL 3 DAY) |
41 |
| - WHERE |
42 |
| - reservation.id = ? |
43 |
| - `, |
44 |
| - [reservation.bookId, candidates[0].id], |
45 |
| - ); |
46 |
| - publishMessage( |
47 |
| - candidates[0].slack, |
48 |
| - `:jiphyeonjeon: 예약 알림 :jiphyeonjeon:\n예약하신 도서 \`${candidates[0].title}\`(이)가 대출 가능합니다. 3일 내로 집현전에 방문해 대출해주세요. (방문하시기 전에 비치 여부를 확인해주세요)`, |
49 |
| - ); |
50 |
| - } |
51 |
| - } catch (e) { |
52 |
| - await conn.rollback(); |
53 |
| - if (e instanceof Error) { |
54 |
| - throw e; |
55 |
| - } |
56 |
| - } finally { |
57 |
| - conn.release(); |
| 8 | + await publishMessage(slack, message); |
| 9 | + } catch (error) { |
| 10 | + logger.error('[scheduler error(slack)]', error); |
58 | 11 | }
|
59 | 12 | };
|
60 | 13 |
|
61 |
| -export const notifyReservation = async () => { |
62 |
| - const reservations: [ |
63 |
| - { |
64 |
| - bookId: number; |
65 |
| - bookInfoId: number; |
66 |
| - }, |
67 |
| - ] = await executeQuery(` |
68 |
| - SELECT |
69 |
| - reservation.bookId AS bookId, |
70 |
| - reservation.bookInfoId AS bookInfoId |
71 |
| - FROM |
72 |
| - reservation |
73 |
| - WHERE |
74 |
| - reservation.status = 3 AND |
75 |
| - DATE(reservation.updatedAt) = CURDATE() |
76 |
| - `); |
77 |
| - reservations.forEach(async (reservation) => { |
78 |
| - if (reservation.bookId) { |
79 |
| - succeedReservation(reservation); |
80 |
| - } |
81 |
| - }); |
82 |
| -}; |
83 |
| - |
84 |
| -export const notifyReservationOverdue = async () => { |
85 |
| - const reservations: { |
86 |
| - slack: string; |
87 |
| - title: string; |
88 |
| - bookId: number; |
89 |
| - bookInfoId: number; |
90 |
| - }[] = await executeQuery(` |
91 |
| - SELECT |
92 |
| - user.slack AS slack, |
93 |
| - book_info.title AS title, |
94 |
| - reservation.bookId AS bookId, |
95 |
| - reservation.bookInfoId AS bookInfoId |
96 |
| - FROM |
97 |
| - reservation |
98 |
| - LEFT JOIN user ON |
99 |
| - user.id = reservation.userId |
100 |
| - LEFT JOIN book_info ON |
101 |
| - book_info.id = reservation.bookInfoId |
102 |
| - WHERE |
103 |
| - reservation.status = 3 AND |
104 |
| - DATEDIFF(CURDATE(), DATE(reservation.endAt)) = 1 |
105 |
| - `); |
106 |
| - reservations.forEach(async (reservation) => { |
107 |
| - publishMessage( |
108 |
| - reservation.slack, |
109 |
| - `:jiphyeonjeon: 예약 만료 알림 :jiphyeonjeon:\n예약하신 도서 \`${reservation.title}\`의 예약이 만료되었습니다.`, |
110 |
| - ); |
111 |
| - const ranks: [{ id: number; createdAt: Date }] = await executeQuery( |
112 |
| - ` |
113 |
| - SELECT |
114 |
| - id, |
115 |
| - createdAt |
116 |
| - FROM |
117 |
| - reservation |
118 |
| - WHERE |
119 |
| - bookInfoId = ? AND status = 0 |
120 |
| - ORDER BY createdAt ASC |
121 |
| - `, |
122 |
| - [reservation.bookInfoId], |
123 |
| - ); |
124 |
| - await executeQuery( |
125 |
| - ` |
126 |
| - UPDATE reservation |
127 |
| - SET |
128 |
| - bookId = ?, |
129 |
| - endAt = ADDDATE(CURDATE(),1) |
130 |
| - WHERE |
131 |
| - id = ? |
132 |
| - `, |
133 |
| - [reservation.bookId, ranks[0].id], |
134 |
| - ); |
135 |
| - }); |
| 14 | +/** |
| 15 | + * 만료된 예약을 처리하고, 다음 예약자에게 할당하고, 슬랙 메시지를 전송합니다. |
| 16 | + * @throws 만료된 예약를 처리하고, 다음 예약자에게 할당하는 쿼리 과정에서 에러가 발생하면 에러를 던집니다. 슬랙 메시지 전송 실패시엔 로그만 남깁니다. |
| 17 | + */ |
| 18 | +export const notifyReservationOverdueAndNotifyReservation = async () => { |
| 19 | + const { overDueReservations, assignedReservations } = await handleReservationOverdueAndAssignReservationToNextWaitingUser(); |
| 20 | + await Promise.allSettled(overDueReservations.map(({slack, title}) => sendSlackMessage(slack, `:jiphyeonjeon: 예약 만료 알림 :jiphyeonjeon:\n예약하신 도서 \`${title}\`의 예약이 만료되었습니다.`))); |
| 21 | + await Promise.allSettled(assignedReservations.map((data) => sendSlackMessage(data!.slack, `:jiphyeonjeon: 예약 알림 :jiphyeonjeon:\n예약하신 도서 \`${data!.title}\`(이)가 대출 가능합니다. 3일 내로 집현전에 방문해 대출해주세요.`,))); |
136 | 22 | };
|
137 | 23 |
|
138 | 24 | /**
|
|
0 commit comments