From 2ea07895a7b28088fa629e5d22f0b27ca4538cb0 Mon Sep 17 00:00:00 2001 From: Gustavo Clemente Date: Thu, 9 May 2024 18:58:19 -0300 Subject: [PATCH 1/8] Added a cron job to ShelterSupply module to run every 30 minutes to change priority of expired supplies (urgent older than 4 hours) --- package-lock.json | 48 ++++++++++++++ package.json | 1 + src/app.module.ts | 2 + src/shelter-supply/constants.ts | 3 + src/shelter-supply/shelter-supply.job.ts | 63 ++++++++++++++++++ src/shelter-supply/shelter-supply.module.ts | 3 +- src/utils/index.ts | 2 + src/utils/utils.ts | 72 +++++++++++++++++++++ 8 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/shelter-supply/constants.ts create mode 100644 src/shelter-supply/shelter-supply.job.ts diff --git a/package-lock.json b/package-lock.json index 6c3ae692..b72af896 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-fastify": "^10.3.8", + "@nestjs/schedule": "^4.0.2", "@nestjs/swagger": "^7.3.1", "@prisma/client": "^5.13.0", "bcrypt": "^5.1.1", @@ -2100,6 +2101,19 @@ } } }, + "node_modules/@nestjs/schedule": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-4.0.2.tgz", + "integrity": "sha512-po9oauE7fO0CjhDKvVC2tzEgjOUwhxYoIsXIVkgfu+xaDMmzzpmXY2s1LT4oP90Z+PaTtPoAHmhslnYmo4mSZg==", + "dependencies": { + "cron": "3.1.7", + "uuid": "9.0.1" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, "node_modules/@nestjs/schematics": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.1.1.tgz", @@ -2543,6 +2557,11 @@ "@types/node": "*" } }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" + }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -4124,6 +4143,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cron": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.7.tgz", + "integrity": "sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==", + "dependencies": { + "@types/luxon": "~3.4.0", + "luxon": "~3.4.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7000,6 +7028,14 @@ "yallist": "^3.0.2" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/magic-string": { "version": "0.30.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", @@ -9632,6 +9668,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/package.json b/package.json index 5e154b46..70abf4c3 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-fastify": "^10.3.8", + "@nestjs/schedule": "^4.0.2", "@nestjs/swagger": "^7.3.1", "@prisma/client": "^5.13.0", "bcrypt": "^5.1.1", diff --git a/src/app.module.ts b/src/app.module.ts index 8b528767..a5f60a78 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,5 +1,6 @@ import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { APP_INTERCEPTOR } from '@nestjs/core'; +import { ScheduleModule } from '@nestjs/schedule'; import { PrismaModule } from './prisma/prisma.module'; import { ShelterModule } from './shelter/shelter.module'; @@ -15,6 +16,7 @@ import { ShelterSupplyModule } from './shelter-supply/shelter-supply.module'; @Module({ imports: [ PrismaModule, + ScheduleModule.forRoot(), UsersModule, SessionsModule, ShelterModule, diff --git a/src/shelter-supply/constants.ts b/src/shelter-supply/constants.ts new file mode 100644 index 00000000..09d71a82 --- /dev/null +++ b/src/shelter-supply/constants.ts @@ -0,0 +1,3 @@ +const priorityExpiryInterval = 4; // In hours + +export { priorityExpiryInterval }; diff --git a/src/shelter-supply/shelter-supply.job.ts b/src/shelter-supply/shelter-supply.job.ts new file mode 100644 index 00000000..662e571d --- /dev/null +++ b/src/shelter-supply/shelter-supply.job.ts @@ -0,0 +1,63 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { Cron, CronExpression } from '@nestjs/schedule'; +import { PrismaService } from '../prisma/prisma.service'; +import { addHours } from '@/utils'; +import { priorityExpiryInterval } from './constants'; +import { SupplyPriority } from '../supply/types'; +import { ShelterSupplyService } from './shelter-supply.service'; + +@Injectable() +export class ShelterSupplyJob { + constructor( + private readonly prismaService: PrismaService, + private readonly shelterSupplyService: ShelterSupplyService, + ) {} + + private readonly logger = new Logger(ShelterSupplyJob.name); + + @Cron(CronExpression.EVERY_30_MINUTES) + async handleCron() { + this.logger.log(`${ShelterSupplyJob.name} running`); + + const expiryDate = addHours( + new Date(Date.now()), + -priorityExpiryInterval, + ).toString(); + + const outatedSupplies = await this.prismaService.shelterSupply.findMany({ + where: { + AND: [ + { priority: SupplyPriority.Urgent }, + { + OR: [ + { + createdAt: { + lte: expiryDate, + }, + }, + { + updatedAt: { + lte: expiryDate, + }, + }, + ], + }, + ], + }, + select: { + supplyId: true, + shelterId: true, + }, + }); + + outatedSupplies.forEach(async (s) => { + const { shelterId, supplyId } = s; + await this.shelterSupplyService.update({ + data: { + priority: SupplyPriority.Needing, + }, + where: { shelterId: shelterId, supplyId: supplyId }, + }); + }); + } +} diff --git a/src/shelter-supply/shelter-supply.module.ts b/src/shelter-supply/shelter-supply.module.ts index 0609a149..3660e5f1 100644 --- a/src/shelter-supply/shelter-supply.module.ts +++ b/src/shelter-supply/shelter-supply.module.ts @@ -3,10 +3,11 @@ import { Module } from '@nestjs/common'; import { ShelterSupplyService } from './shelter-supply.service'; import { ShelterSupplyController } from './shelter-supply.controller'; import { PrismaModule } from '../prisma/prisma.module'; +import { ShelterSupplyJob } from './shelter-supply.job'; @Module({ imports: [PrismaModule], - providers: [ShelterSupplyService], + providers: [ShelterSupplyService, ShelterSupplyJob], controllers: [ShelterSupplyController], }) export class ShelterSupplyModule {} diff --git a/src/utils/index.ts b/src/utils/index.ts index 09934e74..d755ebeb 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -4,6 +4,7 @@ import { getSessionData, deepMerge, capitalize, + addHours, } from './utils'; export { @@ -12,4 +13,5 @@ export { removeNotNumbers, getSessionData, deepMerge, + addHours, }; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 772b3e12..9eb6e395 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -75,10 +75,82 @@ function deepMerge(target: Record, source: Record) { } } +function parseStringToObject(path: string, value: any) { + const keys = path.split('.'); + const currentObj = {}; + let temp = currentObj; + + keys.forEach((key, index) => { + if (index === keys.length - 1) { + temp[key] = value; + } else { + temp[key] = {}; + temp = temp[key]; + } + }); + + return currentObj; +} + +function getSearchWhere(search: string, or?: boolean) { + const where = {}; + if (search !== '') { + const terms = search.split(','); + const groups: Record = + terms.reduce((prev, current) => { + const [key, condition, value] = current.split(':'); + const isBoolean = ['true', 'false'].includes(value); + const mode = + isBoolean || ['in', 'notIn'].includes(condition) + ? undefined + : 'insensitive'; + const parsedValue = isBoolean ? value === 'true' : value; + + return { + ...prev, + [key]: [ + ...(prev[key] ?? []), + { + [condition]: ['in', 'notIn'].includes(condition) + ? [parsedValue] + : parsedValue, + mode, + }, + ], + }; + }, {}); + + const parsed = Object.entries(groups).reduce((prev, [key, current]) => { + if (current.length > 1) { + return { + ...prev, + AND: current.map((c) => parseStringToObject(key, c)), + }; + } else return deepMerge(prev, parseStringToObject(key, current[0])); + }, {}); + Object.assign(where, parsed); + } + if (or) { + return { + OR: Object.entries(where).reduce( + (prev, [key, value]) => [...prev, { [key]: value }], + [] as any[], + ), + }; + } else return where; +} + +function addHours(date: Date, hours: number) { + const result = new Date(); + result.setTime(date.getTime() + hours * 60 * 60 * 1000); + return result; +} + export { ServerResponse, removeNotNumbers, getSessionData, deepMerge, capitalize, + addHours, }; From b05bb715f8243d98a433bb172b15fcf9e4eb3155 Mon Sep 17 00:00:00 2001 From: Gustavo Clemente Date: Thu, 9 May 2024 19:15:20 -0300 Subject: [PATCH 2/8] Fixed typo --- src/shelter-supply/shelter-supply.job.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shelter-supply/shelter-supply.job.ts b/src/shelter-supply/shelter-supply.job.ts index 662e571d..66a3d673 100644 --- a/src/shelter-supply/shelter-supply.job.ts +++ b/src/shelter-supply/shelter-supply.job.ts @@ -24,7 +24,7 @@ export class ShelterSupplyJob { -priorityExpiryInterval, ).toString(); - const outatedSupplies = await this.prismaService.shelterSupply.findMany({ + const outdatedSupplies = await this.prismaService.shelterSupply.findMany({ where: { AND: [ { priority: SupplyPriority.Urgent }, @@ -50,7 +50,7 @@ export class ShelterSupplyJob { }, }); - outatedSupplies.forEach(async (s) => { + outdatedSupplies.forEach(async (s) => { const { shelterId, supplyId } = s; await this.shelterSupplyService.update({ data: { From a7ae2cf170bfd745090fddca54cfff1667a2bb9a Mon Sep 17 00:00:00 2001 From: Gustavo Clemente Date: Thu, 9 May 2024 19:40:18 -0300 Subject: [PATCH 3/8] Fixed to consider createdAt as updatedAt is not being used --- src/shelter-supply/shelter-supply.job.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/shelter-supply/shelter-supply.job.ts b/src/shelter-supply/shelter-supply.job.ts index 66a3d673..c12e7ce6 100644 --- a/src/shelter-supply/shelter-supply.job.ts +++ b/src/shelter-supply/shelter-supply.job.ts @@ -29,18 +29,9 @@ export class ShelterSupplyJob { AND: [ { priority: SupplyPriority.Urgent }, { - OR: [ - { - createdAt: { - lte: expiryDate, - }, - }, - { - updatedAt: { - lte: expiryDate, - }, - }, - ], + createdAt: { + lte: expiryDate, + }, }, ], }, From 701524e0742092b9a0f250b63bf6c9bdf0427e93 Mon Sep 17 00:00:00 2001 From: Gustavo Clemente Date: Fri, 10 May 2024 22:15:21 -0300 Subject: [PATCH 4/8] Refactor made to cover logic using string dates; Code review --- .../shelter-supply-expiration.job.ts | 46 ++++++++++++++++ src/shelter-supply/shelter-supply.job.ts | 54 ------------------- src/shelter-supply/shelter-supply.module.ts | 4 +- 3 files changed, 48 insertions(+), 56 deletions(-) create mode 100644 src/shelter-supply/shelter-supply-expiration.job.ts delete mode 100644 src/shelter-supply/shelter-supply.job.ts diff --git a/src/shelter-supply/shelter-supply-expiration.job.ts b/src/shelter-supply/shelter-supply-expiration.job.ts new file mode 100644 index 00000000..faea4ebf --- /dev/null +++ b/src/shelter-supply/shelter-supply-expiration.job.ts @@ -0,0 +1,46 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { Cron, CronExpression } from '@nestjs/schedule'; +import { PrismaService } from '../prisma/prisma.service'; +import { addHours } from '@/utils'; +import { priorityExpiryInterval } from './constants'; +import { SupplyPriority } from '../supply/types'; +import { ShelterSupplyService } from './shelter-supply.service'; + +@Injectable() +export class ShelterSupplyExpirationJob { + constructor( + private readonly prismaService: PrismaService, + private readonly shelterSupplyService: ShelterSupplyService, + ) {} + + private readonly logger = new Logger(ShelterSupplyExpirationJob.name); + + @Cron(CronExpression.EVERY_10_SECONDS) + async handleCron() { + this.logger.log(`${ShelterSupplyExpirationJob.name} running`); + + const expiryDate = addHours(new Date(Date.now()), -priorityExpiryInterval); + const supplies = await this.prismaService.shelterSupply.findMany({ + select: { + supplyId: true, + shelterId: true, + createdAt: true, + }, + where: { + priority: SupplyPriority.Urgent, + }, + }); + + supplies.forEach(async (s) => { + const { shelterId, supplyId, createdAt } = s; + if (new Date(createdAt) <= expiryDate) { + await this.shelterSupplyService.update({ + data: { + priority: SupplyPriority.Needing, + }, + where: { shelterId: shelterId, supplyId: supplyId }, + }); + } + }); + } +} diff --git a/src/shelter-supply/shelter-supply.job.ts b/src/shelter-supply/shelter-supply.job.ts deleted file mode 100644 index c12e7ce6..00000000 --- a/src/shelter-supply/shelter-supply.job.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { Cron, CronExpression } from '@nestjs/schedule'; -import { PrismaService } from '../prisma/prisma.service'; -import { addHours } from '@/utils'; -import { priorityExpiryInterval } from './constants'; -import { SupplyPriority } from '../supply/types'; -import { ShelterSupplyService } from './shelter-supply.service'; - -@Injectable() -export class ShelterSupplyJob { - constructor( - private readonly prismaService: PrismaService, - private readonly shelterSupplyService: ShelterSupplyService, - ) {} - - private readonly logger = new Logger(ShelterSupplyJob.name); - - @Cron(CronExpression.EVERY_30_MINUTES) - async handleCron() { - this.logger.log(`${ShelterSupplyJob.name} running`); - - const expiryDate = addHours( - new Date(Date.now()), - -priorityExpiryInterval, - ).toString(); - - const outdatedSupplies = await this.prismaService.shelterSupply.findMany({ - where: { - AND: [ - { priority: SupplyPriority.Urgent }, - { - createdAt: { - lte: expiryDate, - }, - }, - ], - }, - select: { - supplyId: true, - shelterId: true, - }, - }); - - outdatedSupplies.forEach(async (s) => { - const { shelterId, supplyId } = s; - await this.shelterSupplyService.update({ - data: { - priority: SupplyPriority.Needing, - }, - where: { shelterId: shelterId, supplyId: supplyId }, - }); - }); - } -} diff --git a/src/shelter-supply/shelter-supply.module.ts b/src/shelter-supply/shelter-supply.module.ts index 3660e5f1..7601d5da 100644 --- a/src/shelter-supply/shelter-supply.module.ts +++ b/src/shelter-supply/shelter-supply.module.ts @@ -3,11 +3,11 @@ import { Module } from '@nestjs/common'; import { ShelterSupplyService } from './shelter-supply.service'; import { ShelterSupplyController } from './shelter-supply.controller'; import { PrismaModule } from '../prisma/prisma.module'; -import { ShelterSupplyJob } from './shelter-supply.job'; +import { ShelterSupplyExpirationJob } from './shelter-supply-expiration.job'; @Module({ imports: [PrismaModule], - providers: [ShelterSupplyService, ShelterSupplyJob], + providers: [ShelterSupplyService, ShelterSupplyExpirationJob], controllers: [ShelterSupplyController], }) export class ShelterSupplyModule {} From c3c7da04fc4c1d23ad261817ddda0b94956b0d12 Mon Sep 17 00:00:00 2001 From: Gustavo Clemente Date: Fri, 10 May 2024 22:21:40 -0300 Subject: [PATCH 5/8] Reviewed --- src/utils/utils.ts | 65 ---------------------------------------------- 1 file changed, 65 deletions(-) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 9eb6e395..9fe32f0e 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -75,71 +75,6 @@ function deepMerge(target: Record, source: Record) { } } -function parseStringToObject(path: string, value: any) { - const keys = path.split('.'); - const currentObj = {}; - let temp = currentObj; - - keys.forEach((key, index) => { - if (index === keys.length - 1) { - temp[key] = value; - } else { - temp[key] = {}; - temp = temp[key]; - } - }); - - return currentObj; -} - -function getSearchWhere(search: string, or?: boolean) { - const where = {}; - if (search !== '') { - const terms = search.split(','); - const groups: Record = - terms.reduce((prev, current) => { - const [key, condition, value] = current.split(':'); - const isBoolean = ['true', 'false'].includes(value); - const mode = - isBoolean || ['in', 'notIn'].includes(condition) - ? undefined - : 'insensitive'; - const parsedValue = isBoolean ? value === 'true' : value; - - return { - ...prev, - [key]: [ - ...(prev[key] ?? []), - { - [condition]: ['in', 'notIn'].includes(condition) - ? [parsedValue] - : parsedValue, - mode, - }, - ], - }; - }, {}); - - const parsed = Object.entries(groups).reduce((prev, [key, current]) => { - if (current.length > 1) { - return { - ...prev, - AND: current.map((c) => parseStringToObject(key, c)), - }; - } else return deepMerge(prev, parseStringToObject(key, current[0])); - }, {}); - Object.assign(where, parsed); - } - if (or) { - return { - OR: Object.entries(where).reduce( - (prev, [key, value]) => [...prev, { [key]: value }], - [] as any[], - ), - }; - } else return where; -} - function addHours(date: Date, hours: number) { const result = new Date(); result.setTime(date.getTime() + hours * 60 * 60 * 1000); From ba821840ea9b4de29ccc0c30a976046080e3ebbd Mon Sep 17 00:00:00 2001 From: Gustavo Clemente Date: Sat, 11 May 2024 00:26:53 -0300 Subject: [PATCH 6/8] Fixed time interval to 30 minutes --- src/shelter-supply/shelter-supply-expiration.job.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shelter-supply/shelter-supply-expiration.job.ts b/src/shelter-supply/shelter-supply-expiration.job.ts index faea4ebf..d4a48db5 100644 --- a/src/shelter-supply/shelter-supply-expiration.job.ts +++ b/src/shelter-supply/shelter-supply-expiration.job.ts @@ -15,7 +15,7 @@ export class ShelterSupplyExpirationJob { private readonly logger = new Logger(ShelterSupplyExpirationJob.name); - @Cron(CronExpression.EVERY_10_SECONDS) + @Cron(CronExpression.EVERY_30_MINUTES) async handleCron() { this.logger.log(`${ShelterSupplyExpirationJob.name} running`); From 84dfc746d3628957257869230a6c667c7fe43590 Mon Sep 17 00:00:00 2001 From: Gustavo Clemente Date: Sat, 11 May 2024 17:07:44 -0300 Subject: [PATCH 7/8] Added constants to .env; changed implementation to new date types and use one db query to update needed supplies --- .env.local | 8 +++- package-lock.json | 48 ------------------- package.json | 1 - src/shelter-supply/constants.ts | 9 +++- .../shelter-supply-expiration.job.ts | 29 ++++------- 5 files changed, 23 insertions(+), 72 deletions(-) diff --git a/.env.local b/.env.local index 9cd74618..288ad4f9 100644 --- a/.env.local +++ b/.env.local @@ -10,4 +10,10 @@ DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_ SECRET_KEY=batata HOST=::0.0.0.0 -PORT=4000 \ No newline at end of file +PORT=4000 + +# In hours +SHELTER_SUPPLY_PRIORITY_EXPIRY_INTERVAL=4 + +# Every 30 minutes +SHELTER_SUPPLY_PRIORITY_JOB_INTERVAL="0 */30 * * * *" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b72af896..6c3ae692 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,6 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-fastify": "^10.3.8", - "@nestjs/schedule": "^4.0.2", "@nestjs/swagger": "^7.3.1", "@prisma/client": "^5.13.0", "bcrypt": "^5.1.1", @@ -2101,19 +2100,6 @@ } } }, - "node_modules/@nestjs/schedule": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-4.0.2.tgz", - "integrity": "sha512-po9oauE7fO0CjhDKvVC2tzEgjOUwhxYoIsXIVkgfu+xaDMmzzpmXY2s1LT4oP90Z+PaTtPoAHmhslnYmo4mSZg==", - "dependencies": { - "cron": "3.1.7", - "uuid": "9.0.1" - }, - "peerDependencies": { - "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0" - } - }, "node_modules/@nestjs/schematics": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.1.1.tgz", @@ -2557,11 +2543,6 @@ "@types/node": "*" } }, - "node_modules/@types/luxon": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", - "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" - }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -4143,15 +4124,6 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "node_modules/cron": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.7.tgz", - "integrity": "sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==", - "dependencies": { - "@types/luxon": "~3.4.0", - "luxon": "~3.4.0" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7028,14 +7000,6 @@ "yallist": "^3.0.2" } }, - "node_modules/luxon": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", - "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", - "engines": { - "node": ">=12" - } - }, "node_modules/magic-string": { "version": "0.30.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", @@ -9668,18 +9632,6 @@ "node": ">= 0.4.0" } }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/package.json b/package.json index 70abf4c3..5e154b46 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-fastify": "^10.3.8", - "@nestjs/schedule": "^4.0.2", "@nestjs/swagger": "^7.3.1", "@prisma/client": "^5.13.0", "bcrypt": "^5.1.1", diff --git a/src/shelter-supply/constants.ts b/src/shelter-supply/constants.ts index 09d71a82..32bab413 100644 --- a/src/shelter-supply/constants.ts +++ b/src/shelter-supply/constants.ts @@ -1,3 +1,8 @@ -const priorityExpiryInterval = 4; // In hours +const jobInterval: string = + process.env.SHELTER_SUPPLY_PRIORITY_JOB_INTERVAL ?? '0 */30 * * * *'; -export { priorityExpiryInterval }; +const priorityExpiryInterval: number = Number.parseInt( + process.env.SHELTER_SUPPLY_PRIORITY_EXPIRY_INTERVAL ?? '4', +); + +export { jobInterval, priorityExpiryInterval }; diff --git a/src/shelter-supply/shelter-supply-expiration.job.ts b/src/shelter-supply/shelter-supply-expiration.job.ts index d4a48db5..5d9cab1d 100644 --- a/src/shelter-supply/shelter-supply-expiration.job.ts +++ b/src/shelter-supply/shelter-supply-expiration.job.ts @@ -1,8 +1,8 @@ import { Injectable, Logger } from '@nestjs/common'; -import { Cron, CronExpression } from '@nestjs/schedule'; +import { Cron } from '@nestjs/schedule'; import { PrismaService } from '../prisma/prisma.service'; import { addHours } from '@/utils'; -import { priorityExpiryInterval } from './constants'; +import { priorityExpiryInterval, jobInterval } from './constants'; import { SupplyPriority } from '../supply/types'; import { ShelterSupplyService } from './shelter-supply.service'; @@ -15,32 +15,21 @@ export class ShelterSupplyExpirationJob { private readonly logger = new Logger(ShelterSupplyExpirationJob.name); - @Cron(CronExpression.EVERY_30_MINUTES) + @Cron(jobInterval) async handleCron() { this.logger.log(`${ShelterSupplyExpirationJob.name} running`); const expiryDate = addHours(new Date(Date.now()), -priorityExpiryInterval); - const supplies = await this.prismaService.shelterSupply.findMany({ - select: { - supplyId: true, - shelterId: true, - createdAt: true, + await this.prismaService.shelterSupply.updateMany({ + data: { + priority: SupplyPriority.Needing, }, where: { priority: SupplyPriority.Urgent, + createdAt: { + lte: expiryDate, + }, }, }); - - supplies.forEach(async (s) => { - const { shelterId, supplyId, createdAt } = s; - if (new Date(createdAt) <= expiryDate) { - await this.shelterSupplyService.update({ - data: { - priority: SupplyPriority.Needing, - }, - where: { shelterId: shelterId, supplyId: supplyId }, - }); - } - }); } } From 60553f782c16c45adefb1676e881718c0081b077 Mon Sep 17 00:00:00 2001 From: Gustavo Clemente Date: Sat, 11 May 2024 21:45:26 -0300 Subject: [PATCH 8/8] Bug fixes; linter fix --- package-lock.json | 48 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 49 insertions(+) diff --git a/package-lock.json b/package-lock.json index 6c3ae692..b72af896 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-fastify": "^10.3.8", + "@nestjs/schedule": "^4.0.2", "@nestjs/swagger": "^7.3.1", "@prisma/client": "^5.13.0", "bcrypt": "^5.1.1", @@ -2100,6 +2101,19 @@ } } }, + "node_modules/@nestjs/schedule": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-4.0.2.tgz", + "integrity": "sha512-po9oauE7fO0CjhDKvVC2tzEgjOUwhxYoIsXIVkgfu+xaDMmzzpmXY2s1LT4oP90Z+PaTtPoAHmhslnYmo4mSZg==", + "dependencies": { + "cron": "3.1.7", + "uuid": "9.0.1" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, "node_modules/@nestjs/schematics": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.1.1.tgz", @@ -2543,6 +2557,11 @@ "@types/node": "*" } }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" + }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -4124,6 +4143,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cron": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.7.tgz", + "integrity": "sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==", + "dependencies": { + "@types/luxon": "~3.4.0", + "luxon": "~3.4.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7000,6 +7028,14 @@ "yallist": "^3.0.2" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/magic-string": { "version": "0.30.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", @@ -9632,6 +9668,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/package.json b/package.json index 5e154b46..70abf4c3 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-fastify": "^10.3.8", + "@nestjs/schedule": "^4.0.2", "@nestjs/swagger": "^7.3.1", "@prisma/client": "^5.13.0", "bcrypt": "^5.1.1",