scheduled cleanup jobs

This commit is contained in:
mrjvs
2023-10-29 17:15:07 +01:00
parent 91750a5086
commit b6b6288a7a
7 changed files with 86 additions and 1 deletions

View File

@@ -29,7 +29,7 @@ Backend for movie-web
- [X] catpcha support - [X] catpcha support
- [X] global namespacing (accounts are stored on a namespace) - [X] global namespacing (accounts are stored on a namespace)
- [ ] cleanup jobs - [ ] cleanup jobs
- [ ] cleanup expired sessions - [X] cleanup expired sessions
- [ ] cleanup old provider metrics - [ ] cleanup old provider metrics
## Second todo list ## Second todo list

View File

@@ -36,6 +36,7 @@
"@fastify/cors": "^8.3.0", "@fastify/cors": "^8.3.0",
"@mikro-orm/core": "^5.9.0", "@mikro-orm/core": "^5.9.0",
"@mikro-orm/postgresql": "^5.9.0", "@mikro-orm/postgresql": "^5.9.0",
"cron": "^3.1.5",
"fastify": "^4.21.0", "fastify": "^4.21.0",
"fastify-metrics": "^10.3.2", "fastify-metrics": "^10.3.2",
"fastify-type-provider-zod": "^1.1.9", "fastify-type-provider-zod": "^1.1.9",

19
pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ dependencies:
'@mikro-orm/postgresql': '@mikro-orm/postgresql':
specifier: ^5.9.0 specifier: ^5.9.0
version: 5.9.0(@mikro-orm/core@5.9.0) version: 5.9.0(@mikro-orm/core@5.9.0)
cron:
specifier: ^3.1.5
version: 3.1.5
fastify: fastify:
specifier: ^4.21.0 specifier: ^4.21.0
version: 4.24.3 version: 4.24.3
@@ -432,6 +435,10 @@ packages:
'@types/node': 20.8.9 '@types/node': 20.8.9
dev: true dev: true
/@types/luxon@3.3.3:
resolution: {integrity: sha512-/BJF3NT0pRMuxrenr42emRUF67sXwcZCd+S1ksG/Fcf9O7C3kKCY4uJSbKBE4KDUIYr3WMsvfmWD8hRjXExBJQ==}
dev: false
/@types/node@20.8.9: /@types/node@20.8.9:
resolution: {integrity: sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==} resolution: {integrity: sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==}
dependencies: dependencies:
@@ -892,6 +899,13 @@ packages:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
dev: true dev: true
/cron@3.1.5:
resolution: {integrity: sha512-e/ivHUhSZVvF5PUqgj7dzQ96KqAhK1/peMDr5Mmfm/vEho01/O+ySJnhTBJ2JPvFEWXpjLESIJBke0ZpZ7r7FA==}
dependencies:
'@types/luxon': 3.3.3
luxon: 3.4.3
dev: false
/cross-spawn@7.0.3: /cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@@ -1830,6 +1844,11 @@ packages:
dependencies: dependencies:
yallist: 4.0.0 yallist: 4.0.0
/luxon@3.4.3:
resolution: {integrity: sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==}
engines: {node: '>=12'}
dev: false
/make-error@1.3.6: /make-error@1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
dev: true dev: true

View File

@@ -1,4 +1,5 @@
import { setupFastify, startFastify } from '@/modules/fastify'; import { setupFastify, startFastify } from '@/modules/fastify';
import { setupJobs } from '@/modules/jobs';
import { setupMetrics } from '@/modules/metrics'; import { setupMetrics } from '@/modules/metrics';
import { setupMikroORM } from '@/modules/mikro'; import { setupMikroORM } from '@/modules/mikro';
import { scopedLogger } from '@/services/logger'; import { scopedLogger } from '@/services/logger';
@@ -13,6 +14,7 @@ async function bootstrap(): Promise<void> {
const app = await setupFastify(); const app = await setupFastify();
await setupMikroORM(); await setupMikroORM();
await setupMetrics(app); await setupMetrics(app);
await setupJobs();
await startFastify(app); await startFastify(app);

View File

@@ -0,0 +1,5 @@
import { sessionExpiryJob } from '@/modules/jobs/list/sessionExpiry';
export async function setupJobs() {
sessionExpiryJob.start();
}

43
src/modules/jobs/job.ts Normal file
View File

@@ -0,0 +1,43 @@
import { getORM } from '@/modules/mikro';
import { scopedLogger } from '@/services/logger';
import { EntityManager } from '@mikro-orm/postgresql';
import { CronJob } from 'cron';
const minOffset = 0;
const maxOffset = 60 * 4;
const secondsOffset =
Math.floor(Math.random() * (maxOffset - minOffset)) + minOffset;
const log = scopedLogger('jobs');
const wait = (sec: number) =>
new Promise<void>((resolve) => {
setTimeout(() => resolve(), sec * 1000);
});
/**
* @param cron crontime in this order: (min of hour) (hour of day) (day of month) (day of week) (sec of month)
*/
export function job(
cron: string,
cb: (ctx: { em: EntityManager }) => Promise<void>,
): CronJob {
return CronJob.from({
cronTime: cron,
onTick: async () => {
// offset by random amount of seconds, just to prevent jobs running at
// the same time when running multiple instances
await wait(secondsOffset);
// actually run the job
try {
const em = getORM().em.fork();
await cb({ em });
} catch (err) {
log.error('Failed to run job!');
log.error(err);
}
},
start: false,
});
}

View File

@@ -0,0 +1,15 @@
import { Session } from '@/db/models/Session';
import { job } from '@/modules/jobs/job';
// every day at 12:00:00
export const sessionExpiryJob = job('0 12 * * *', async ({ em }) => {
await em
.createQueryBuilder(Session)
.delete()
.where({
expiresAt: {
$lt: new Date(),
},
})
.execute();
});