diff --git a/adminPage/handlers/event.ts b/adminPage/handlers/event.ts index 6f77b27..45f348b 100644 --- a/adminPage/handlers/event.ts +++ b/adminPage/handlers/event.ts @@ -2,6 +2,8 @@ import { ActionHandler, Filter, SortSetter, flat, populator } from "adminjs"; import Event from "../../models/events.js"; import { redisClient } from "../../redis/connect.js"; import { EventActionQueryParameters } from "./index.js"; +import { IEvent } from "../../models/types.js"; +import { delEventSchedule, setEventSchedule } from "../../redis/schedule.js"; const list: ActionHandler = async (request, response, context) => { const { query } = request; // 요청 url의 query 부분 추출 @@ -85,15 +87,24 @@ const after = (action: "edit" | "new") => async (originalResponse, request, cont const hasError = Object.keys(originalResponse.record.errors).length; // checking if object doesn't have any errors or is a edit action if (isPost && isEdit && hasRecord && !hasError) { + const {id, end} = hasRecord // 학과는 로그인한 관리자의 것으로 적용 if (role != "관리자") { hasRecord.major_advisor = role; } // redis 캐싱 - const redisKeyEach = `event:${hasRecord.id}`; + const redisKeyEach = `event:${id}`; const redisKeyAll = "allEvents"; - await redisClient.set(redisKeyEach, JSON.stringify(hasRecord)); + // end날이 아직 안 지났다면 + if (end > new Date()) { + // 종료 변경하는 스케쥴 등록 + console.log("has update::?",hasRecord.update); + const recordModel = (await Event.findOne({ + where: {id} + })) as IEvent; + setEventSchedule(recordModel); + } // 전체 목록 캐싱 const allEventsFromDb = await Event.findAll({ where: { @@ -114,9 +125,14 @@ const deleteAfter = () => async (originalResponse, request, context) => { // checking if object doesn't have any errors or is a edit action if (isPost && isAction && record) { - await redisClient.del(`event:${record.id}`); - + const {id, end} = record; const redisKeyAll = "allEvents"; + + await redisClient.del(`event:${id}`); + + if (end > new Date()) { + delEventSchedule(record); + } // 전체 목록 캐싱 const allEventsFromDb = await Event.findAll({ where: { @@ -140,17 +156,21 @@ const bulkDelete = () => async (originalResponse, request, context) => { records.forEach(async ({params: record}) => { // redis 캐싱 제거 await redisClient.del(`event:${record.id}`); + if (record.end > new Date()) { + // 스케쥴에 등록된 행사들 제거 + delEventSchedule(record); + } + }); + const redisKeyAll = "allEvents"; + // 전체 목록 캐싱 + const allEventsFromDb = await Event.findAll({ + where: { + expired: false, // 진행중인 행사만 가져오기 + }, + order: [["start", "ASC"]], }); + await redisClient.set(redisKeyAll, JSON.stringify(allEventsFromDb)); } - const redisKeyAll = "allEvents"; - // 전체 목록 캐싱 - const allEventsFromDb = await Event.findAll({ - where: { - expired: false, // 진행중인 행사만 가져오기 - }, - order: [["start", "ASC"]], - }); - await redisClient.set(redisKeyAll, JSON.stringify(allEventsFromDb)); return originalResponse; }; diff --git a/models/events.ts b/models/events.ts index 16673df..296d03f 100644 --- a/models/events.ts +++ b/models/events.ts @@ -76,5 +76,4 @@ const Event = sequelize.define( timestamps: false, // createdAt 및 updatedAt 필드 생성 방지 } ); - export default Event \ No newline at end of file diff --git a/redis/caching.ts b/redis/caching.ts index e685bc4..65a1cea 100644 --- a/redis/caching.ts +++ b/redis/caching.ts @@ -3,7 +3,7 @@ import Linktree from "../models/linktree.js"; import Notice from "../models/notice.js"; import { IEvent, INotice } from "../models/types.js"; import { redisClient } from "./connect.js"; -import { getNextDay, setNoticeSchedule } from "./schedule.js"; +import { getNextDay, setEventSchedule, setNoticeSchedule } from "./schedule.js"; export const initAllLinktrees = async () => { const redisKey = "linktrees"; @@ -33,6 +33,7 @@ export const initAllLinktrees = async () => { export const initAllOngoingEvents = async () => { const redisKey = "allEvents"; const eachEvents = await redisClient.keys(`event:*`); + const currentDate = new Date(); const eventsFromDb = (await Event.findAll({ where: { expired: false, // 진행중인 행사만 가져오기 @@ -48,6 +49,14 @@ export const initAllOngoingEvents = async () => { } for (const event of eventsFromDb) { const eventRedisKey = `event:${event.id}`; + // 종료 전이면 + if (event.end > currentDate) { + // 종료 날에 종료되도록 스케쥴링 + setEventSchedule(event); + } else { // 종료 됐으면 + // 종료로 변경 + event.update({...event, expired: true}); + } await redisClient.set(eventRedisKey, JSON.stringify(event)); } diff --git a/redis/schedule.ts b/redis/schedule.ts index f0c6582..aca61e9 100644 --- a/redis/schedule.ts +++ b/redis/schedule.ts @@ -1,41 +1,94 @@ import { Job, scheduleJob } from "node-schedule"; -import { INotice } from "../models/types.js"; +import { IEvent, INotice } from "../models/types.js"; import { cachingAllNotices } from "./caching.js"; import { redisClient } from "./connect.js"; +import Event from "../models/events.js"; const jobArray: Job[] = []; export const setNoticeSchedule = (row: INotice) => { const { id, date } = row; - const job = scheduleJob(`${id}`, getNextDay(date), async function () { - console.log("run schedule:", id, date.toLocaleString(), "to 일반"); + const key = `notice:${id}`; + const job = scheduleJob(key, getNextDay(date), async function () { + console.log("run schedule:", key, date.toLocaleString(), "to 일반"); const updatedRow = await row.update({ ...row, priority: "일반" }); - await redisClient.set(`notice:${id}`, JSON.stringify(updatedRow)); + await redisClient.set(key, JSON.stringify(updatedRow)); // 전체 긴급 공지 목록 캐싱 await cachingAllNotices(); jobArray.splice(existJobIndex, 1); }); - console.log({jobArray}) - const existJobIndex = jobArray.findIndex(j => j?.name == `${id}`); + const existJobIndex = jobArray.findIndex((j) => j?.name == key); if (existJobIndex > -1) { jobArray[existJobIndex].cancel(); jobArray[existJobIndex] = job; } else { jobArray.push(job); } - console.log('set schedule:', `${id}-${date.toLocaleString()}`); - console.log('job list:', jobArray.map(j => j?.name)); + console.log("set schedule:", `${key}-${date.toLocaleString()}`); + console.log( + "job list:", + jobArray.map((j) => j?.name) + ); }; export const delNoticeSchedule = (row: INotice) => { - const {id, date} = row; - const existJobIndex = jobArray.findIndex(j => j.name == `${id}`); + const { id, date } = row; + const key = `notice:${id}`; + const existJobIndex = jobArray.findIndex((j) => j.name == `${key}`); if (existJobIndex > -1) { jobArray[existJobIndex].cancel(); jobArray.splice(existJobIndex, 1); - console.log('del schedule:', `${id}-${date.toLocaleString()}`); - console.log('job list:', jobArray.map(j => j?.name)); + console.log("del schedule:", `${key}-${date.toLocaleString()}`); + console.log( + "job list:", + jobArray.map((j) => j?.name) + ); } else { - console.warn(`jobArray hasn't schedule-${id}`); + console.warn(`jobArray hasn't schedule-${key}`); } -} - -export const getNextDay = (date: Date) => date.setDate(date.getDate() + 1); \ No newline at end of file +}; +export const setEventSchedule = (row: IEvent) => { + const { id, end } = row; + const key = `event:${id}`; + const job = scheduleJob(key, end, async function () { + console.log("run schedule:", key, end.toLocaleString(), "to 행사 종료"); + const updatedRow = await row.update({ ...row, expired: true }); + await redisClient.set(key, JSON.stringify(updatedRow)); + // 전체 행사 목록 캐싱 + const allEventsFromDb = await Event.findAll({ + where: { + expired: false, // 진행중인 행사만 가져오기 + }, + order: [["start", "ASC"]], + }); + await redisClient.set("allEvents", JSON.stringify(allEventsFromDb)); + jobArray.splice(existJobIndex, 1); + }); + const existJobIndex = jobArray.findIndex((j) => j?.name == key); + if (existJobIndex > -1) { + jobArray[existJobIndex].cancel(); + jobArray[existJobIndex] = job; + } else { + jobArray.push(job); + } + console.log("set schedule:", `${key}-${end.toLocaleString()}`); + console.log( + "job list:", + jobArray.map((j) => j?.name) + ); +}; +export const delEventSchedule = (row: IEvent) => { + const { id, end } = row; + const key = `event:${id}`; + const existJobIndex = jobArray.findIndex((j) => j.name == `${key}`); + if (existJobIndex > -1) { + jobArray[existJobIndex].cancel(); + jobArray.splice(existJobIndex, 1); + console.log("del schedule:", `${key}-${end.toLocaleString()}`); + console.log( + "job list:", + jobArray.map((j) => j?.name) + ); + } else { + console.warn(`jobArray hasn't schedule-${key}`); + } +}; +export const getNextDay = (date: Date) => date.setDate(date.getDate() + 1);