From 168dffbaa6d39f4229a6ed53cb46190cc120baf8 Mon Sep 17 00:00:00 2001 From: Zac Date: Sun, 19 Nov 2023 22:47:25 -0600 Subject: [PATCH] Update: Improved scheduler (#19) --- package-lock.json | 42 +++++++++++++++----------------------- src/app.ts | 5 ++++- src/lib/episodeNotifier.ts | 28 +++++++++++++++---------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/package-lock.json b/package-lock.json index e68cfae..68cb566 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "name": "TVBot", "dependencies": { "@codedependant/semantic-release-docker": "^4.4.0", "@prisma/client": "^5.0.0", @@ -770,6 +771,14 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "engines": { + "node": ">=14" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", @@ -1703,9 +1712,9 @@ } }, "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -1758,17 +1767,6 @@ "semver": "^7.0.0" } }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -8798,14 +8796,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -9231,11 +9221,11 @@ } }, "node_modules/undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", "dependencies": { - "busboy": "^1.6.0" + "@fastify/busboy": "^2.0.0" }, "engines": { "node": ">=14.0" diff --git a/src/app.ts b/src/app.ts index 4d8753f..d4713d3 100644 --- a/src/app.ts +++ b/src/app.ts @@ -68,11 +68,14 @@ export class App { void setRandomShowActivity(user) }) + schedule.scheduleJob('lifecycle:10min:announceEpisodes', '5-55/10 * * * *', async () => { + void scheduleAiringMessages(this) + }) + schedule.scheduleJob('lifecycle:4hours:fetchEpisoded', '0 */4 * * *', async () => { setTVDBLoadingActivity(user) await pruneUnsubscribedShows() await checkForAiringEpisodes() - await scheduleAiringMessages(this) void setRandomShowActivity(user) }) diff --git a/src/lib/episodeNotifier.ts b/src/lib/episodeNotifier.ts index 4fc7295..23e17e3 100644 --- a/src/lib/episodeNotifier.ts +++ b/src/lib/episodeNotifier.ts @@ -21,28 +21,34 @@ export interface NotificationPayload { episodeNumbers: number[] } +type PayloadCollection = Collection + /** * look through episodes in the db and schedule notifications to the defined destinations * @param app instance of the main app */ export async function scheduleAiringMessages (app: App): Promise { + const nowUtc = moment.utc() + const tenMinutesFromNow = nowUtc.add(10, 'minutes') + const showsWithEpisodes = await client.show.findMany({ where: { episodes: { some: { - messageSent: false + messageSent: false, + airDate: { + lte: tenMinutesFromNow.toDate() + } } } } }) // convert the shows into a collection of notification payloads - const payloadCollection = showsWithEpisodes.reduce(reduceEpisodes, new Collection()) + const payloadCollection: PayloadCollection = showsWithEpisodes.reduce(reduceEpisodes, new Collection()) - // grab the discord client and global destinations for the schedule jobs to use const discord = app.getClient() const settingsManager = app.getSettingsManager() - // const globalDestinations = app.getSettings()?.allEpisodes ?? [] for (const payload of payloadCollection.values()) { await scheduleJob(payload, discord, settingsManager) @@ -55,20 +61,20 @@ export async function scheduleAiringMessages (app: App): Promise { * @param show current show to process * @returns collection of notification payloads */ -export function reduceEpisodes (acc: Collection, show: Show): Collection { +function reduceEpisodes ( + acc: Collection, + show: Show +): Collection { const momentUTC = moment.utc(new Date()) for (const e of show.episodes) { const airDate = moment.utc(e.airDate) - const inTimeWindow = airDate.isSameOrAfter(momentUTC) && airDate.isSameOrBefore(momentUTC.clone().add('1', 'day')) + const inTimeWindow = airDate.isSameOrAfter(momentUTC) && airDate.isSameOrBefore(momentUTC.clone().add(10, 'minutes')) if (!inTimeWindow) continue - const airDateString = moment.utc(e.airDate) - .tz(process.env.TZ ?? 'America/Chicago') - .format('YYYY-MM-DD@HH:mm') - - const key = `announceEpisodes:${airDateString}:${show.imdbId}:S${addLeadingZeros(e.season, 2)}` + const key = `announceEpisodes:${show.imdbId}:S${addLeadingZeros(e.season, 2)}` // define the default payload to use if one doesn't exist in the collection const defaultPayload: NotificationPayload = {