mirror of
https://github.com/movie-web/backend.git
synced 2025-09-13 16:33:26 +00:00
scheduled cleanup jobs
This commit is contained in:
@@ -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
|
||||||
|
@@ -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
19
pnpm-lock.yaml
generated
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
5
src/modules/jobs/index.ts
Normal file
5
src/modules/jobs/index.ts
Normal 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
43
src/modules/jobs/job.ts
Normal 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,
|
||||||
|
});
|
||||||
|
}
|
15
src/modules/jobs/list/sessionExpiry.ts
Normal file
15
src/modules/jobs/list/sessionExpiry.ts
Normal 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();
|
||||||
|
});
|
Reference in New Issue
Block a user