Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/#182: 공지사항 크롤링 비동기처리 추가 및 무한 슬랙알림 문제 해결 #184

Merged
merged 4 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 87 additions & 48 deletions src/db/data/noticeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface PushNoti {

interface NotiLink {
link: string;
rep_yn: boolean;
}

export const saveDepartmentToDB = async (college: College[]): Promise<void> => {
Expand Down Expand Up @@ -74,81 +75,119 @@ const convertAllNoticeToNormalNotice = async (
}
};

const convertSpecificNoticeToPinnedNotice = async (
const convertSpecificNoticePinned = async (
tableName: string,
noticeLink: string,
isPinned: boolean,
connection?: PoolConnection,
): Promise<void> => {
const query = `UPDATE ${tableName} SET rep_yn = true WHERE link = '${noticeLink}';`;
const query = `UPDATE ${tableName} SET rep_yn = ${isPinned} WHERE link = '${noticeLink}';`;

try {
await db.execute(query);
if (connection) await connection.execute(query);
else await db.execute(query);
} catch (error) {
console.log(error.message + '고정 공지로 변경 실패');
// notificationToSlack(error.message + '\n 고정 공지로 변경 실패');
}
};

export const saveMajorNoticeToDB = async (
connection?: PoolConnection,
): Promise<PushNoti> => {
await convertAllNoticeToNormalNotice('major_notices', connection);
export const saveMajorNoticeToDB = async (): Promise<PushNoti> => {
// await convertAllNoticeToNormalNotice('major_notices', connection);
const query = 'SELECT * FROM departments;';
const colleges = await selectQuery<College[]>(query, connection);

const getNotiLinkQuery = `SELECT link FROM major_notices;`;
const noticeLinksInDB = (
await selectQuery<NotiLink[]>(getNotiLinkQuery, connection)
).map((noticeLink) => noticeLink.link);
const colleges = await selectQuery<College[]>(query);

const savePromises: Promise<void>[] = [];
const newNoticeMajor: PushNoti = {};
const failedMajor: number[] = [];

for (const college of colleges) {
console.log(college.id);
const noticeLink = await noticeCrawling(college);
const noticeLists = await noticeListCrawling(noticeLink);

const normalNotices = noticeLists.normalNotice;
const pinnedNotices = noticeLists.pinnedNotice;

if (normalNotices.length === 0) {
notificationToSlack(`${noticeLink} 크롤링 실패`);
continue;
}

for (const notice of normalNotices) {
const result = await noticeContentCrawling(notice);
if (result.link === '') {
// notificationToSlack(`${notice} 콘텐츠 크롤링 실패`);
continue;
const savePromises = colleges.map(async (college) => {
const connection = await db.getConnection();
await connection.beginTransaction();
try {
const noticeLink = await noticeCrawling(college);
const noticeLists = await noticeListCrawling(noticeLink);
const pinnedNotices = noticeLists.pinnedNotice;
const normalNotices = noticeLists.normalNotice;
if (normalNotices.length === 0) {
notificationToSlack(`${noticeLink} 크롤링 실패`);
connection.release();
return;
}

if (noticeLinksInDB.includes(result.link)) continue;
if (!newNoticeMajor[college.id]) newNoticeMajor[college.id] = [];
newNoticeMajor[college.id].push(result.title);
savePromises.push(saveMajorNotice(result, college.id, false, connection));
}

if (pinnedNotices) {
for (const notice of pinnedNotices) {
const getNotiLinkQuery = `SELECT link, rep_yn FROM major_notices WHERE department_id = '${college.id}'`;
const noticeDataInDB = await selectQuery<NotiLink[]>(
getNotiLinkQuery,
connection,
);
const noticeLinksInDB = noticeDataInDB.map((noti) => noti.link);
const pinnedNoticeLinksInDB = noticeDataInDB
.filter((noti) => noti.rep_yn)
.map((noti) => noti.link);

for (const notice of normalNotices) {
const result = await noticeContentCrawling(notice);
if (result.link === '') {
notificationToSlack(`${notice} 콘텐츠 크롤링 실패`);
// notificationToSlack(`${notice} 콘텐츠 크롤링 실패`);
continue;
}

if (!noticeLinksInDB.includes(result.link)) {
savePromises.push(
saveMajorNotice(result, college.id, true, connection),
if (noticeLinksInDB.includes(result.link)) return;
if (!newNoticeMajor[college.id]) newNoticeMajor[college.id] = [];
newNoticeMajor[college.id].push(result.title);
saveMajorNotice(result, college.id, false, connection);
noticeLinksInDB.push(result.link);
}

if (pinnedNotices) {
await pinnedNoticeLinksInDB
.filter((noti) => !pinnedNotices.includes(noti))
.map(
async (noti) =>
await convertSpecificNoticePinned(
'major_notices',
noti,
false,
connection,
),
);
continue;
for (const notice of pinnedNotices) {
const result = await noticeContentCrawling(notice);
if (result.link === '') {
notificationToSlack(`${notice} 콘텐츠 크롤링 실패`);
continue;
}

if (!noticeLinksInDB.includes(result.link)) {
saveMajorNotice(result, college.id, true, connection);
continue;
}

if (!pinnedNoticeLinksInDB.includes(result.link))
convertSpecificNoticePinned(
'major_notices',
result.link,
true,
connection,
);
}
convertSpecificNoticeToPinnedNotice('major_notices', result.link);
}

connection.commit();
} catch (error) {
notificationToSlack(college.id + '크롤링 실패' + error.message);
failedMajor.push(college.id);
connection.rollback();
} finally {
connection.release();
}
}
});

await Promise.all(savePromises);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확실히 Promise.all을 사용해서 비동기를 병렬로 처리하니 시간이 훨씬 줄어들었네요.
기존에는 n시 19분 쯤에 항상 알림이 왔던 것 같은데, 최근에는 4분정도에 오더라고요

if (failedMajor.length !== 0) {
const failedMajorList = failedMajor.join();
notificationToSlack('크롤링 실패한 학과: ' + failedMajorList);
}

return newNoticeMajor;
};

Expand Down Expand Up @@ -188,7 +227,7 @@ export const saveSchoolNoticeToDB = async (): Promise<void> => {

for (const noticeLink of pinnedNotices) {
if (schoolNoticeLinksInDB.includes(noticeLink)) {
await convertSpecificNoticeToPinnedNotice('notices', noticeLink);
await convertSpecificNoticePinned('notices', noticeLink, true);
continue;
}

Expand Down
24 changes: 12 additions & 12 deletions src/hooks/cronNoticeCrawling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,34 @@ const pushToUsers = async (pushNotiToUserLists: PushNoti) => {
if (pushedUserCount.length !== 0) notificationToSlack(pushedUserCount);
};

const cronNoticeCrawling = async () => {
const connection = await db.getConnection();
await connection.beginTransaction();
const cronNoticeCrawling = async (reTryCount = 0) => {
try {
const pushNotiToUserLists = await saveMajorNoticeToDB(connection);
const pushNotiToUserLists = await saveMajorNoticeToDB();
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1; // 월은 0부터 시작하므로 1을 더해줍니다.
const day = today.getDate();
notificationToSlack(`${year}-${month}-${day} 크롤링 완료`);
await connection.commit();
pushToUsers(pushNotiToUserLists);
} catch (error) {
await connection.rollback();
notificationToSlack(error.message);
cronNoticeCrawling();
} finally {
connection.release();
if (reTryCount >= 2) {
notificationToSlack(error.message);
return;
}
cronNoticeCrawling(reTryCount + 1);
}
};

const cronExtracurricularCrawling = async () => {
const cronExtracurricularCrawling = async (reTryCount = 0) => {
try {
await saveSchoolNoticeToDB();
await saveLanguageNoticeToDB();
await saveWhalebeToDB();
} catch (error) {
notificationToSlack(error.message);
if (reTryCount >= 2) {
notificationToSlack(error.message);
return;
}
cronExtracurricularCrawling();
}
};
Expand Down
Loading