mirror of
https://github.com/movie-web/backend.git
synced 2025-09-13 13:03:26 +00:00
Split user deletion job and add more job logs
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
|
import { challengeCodeJob } from '@/modules/jobs/list/challengeCode';
|
||||||
import { sessionExpiryJob } from '@/modules/jobs/list/sessionExpiry';
|
import { sessionExpiryJob } from '@/modules/jobs/list/sessionExpiry';
|
||||||
|
import { userDeletionJob } from '@/modules/jobs/list/userDeletion';
|
||||||
|
|
||||||
export async function setupJobs() {
|
export async function setupJobs() {
|
||||||
|
challengeCodeJob.start();
|
||||||
sessionExpiryJob.start();
|
sessionExpiryJob.start();
|
||||||
|
userDeletionJob.start();
|
||||||
}
|
}
|
||||||
|
@@ -20,9 +20,11 @@ const wait = (sec: number) =>
|
|||||||
* @param cron crontime in this order: (min of hour) (hour of day) (day of month) (day of week) (sec of month)
|
* @param cron crontime in this order: (min of hour) (hour of day) (day of month) (day of week) (sec of month)
|
||||||
*/
|
*/
|
||||||
export function job(
|
export function job(
|
||||||
|
name: string,
|
||||||
cron: string,
|
cron: string,
|
||||||
cb: (ctx: { em: EntityManager; log: Logger }) => Promise<void>,
|
cb: (ctx: { em: EntityManager; log: Logger }) => Promise<void>,
|
||||||
): CronJob {
|
): CronJob {
|
||||||
|
log.info(`Registering job '${name}' with cron '${cron}'`);
|
||||||
return CronJob.from({
|
return CronJob.from({
|
||||||
cronTime: cron,
|
cronTime: cron,
|
||||||
onTick: async () => {
|
onTick: async () => {
|
||||||
@@ -33,9 +35,10 @@ export function job(
|
|||||||
// actually run the job
|
// actually run the job
|
||||||
try {
|
try {
|
||||||
const em = getORM().em.fork();
|
const em = getORM().em.fork();
|
||||||
|
log.info(`Starting job '${name}' with cron '${cron}'`);
|
||||||
await cb({ em, log });
|
await cb({ em, log });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error('Failed to run job!');
|
log.error(`Failed to run '${name}' job!`);
|
||||||
log.error(err);
|
log.error(err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -2,14 +2,18 @@ import { ChallengeCode } from '@/db/models/ChallengeCode';
|
|||||||
import { job } from '@/modules/jobs/job';
|
import { job } from '@/modules/jobs/job';
|
||||||
|
|
||||||
// every day at 12:00:00
|
// every day at 12:00:00
|
||||||
export const sessionExpiryJob = job('0 12 * * *', async ({ em }) => {
|
export const challengeCodeJob = job(
|
||||||
await em
|
'Challenge Code Expiry',
|
||||||
.createQueryBuilder(ChallengeCode)
|
'0 12 * * *',
|
||||||
.delete()
|
async ({ em }) => {
|
||||||
.where({
|
await em
|
||||||
expiresAt: {
|
.createQueryBuilder(ChallengeCode)
|
||||||
$lt: new Date(),
|
.delete()
|
||||||
},
|
.where({
|
||||||
})
|
expiresAt: {
|
||||||
.execute();
|
$lt: new Date(),
|
||||||
});
|
},
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
@@ -1,49 +1,56 @@
|
|||||||
import { Session } from '@/db/models/Session';
|
import { Session } from '@/db/models/Session';
|
||||||
import { User } from '@/db/models/User';
|
import { User } from '@/db/models/User';
|
||||||
import { job } from '@/modules/jobs/job';
|
import { job } from '@/modules/jobs/job';
|
||||||
|
|
||||||
// every day at 12:00:00
|
// every day at 12:00:00
|
||||||
export const sessionExpiryJob = job('0 12 * * *', async ({ em, log }) => {
|
export const sessionExpiryJob = job(
|
||||||
const deletedSessions = await em
|
'Session Expiry',
|
||||||
.createQueryBuilder(Session)
|
'0 12 * * *',
|
||||||
.delete()
|
async ({ em, log }) => {
|
||||||
.where({
|
const deletedSessions = await em
|
||||||
expiresAt: {
|
.createQueryBuilder(Session)
|
||||||
$lt: new Date(),
|
.delete()
|
||||||
},
|
.where({
|
||||||
})
|
expiresAt: {
|
||||||
.execute<{ affectedRows: number }>('run');
|
$lt: new Date(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.execute<{ affectedRows: number }>('run');
|
||||||
|
|
||||||
log.info(`Removed ${deletedSessions.affectedRows} sessions that had expired`);
|
log.info(
|
||||||
|
`Removed ${deletedSessions.affectedRows} sessions that had expired`,
|
||||||
|
);
|
||||||
|
|
||||||
const knex = em.getKnex();
|
const knex = em.getKnex();
|
||||||
|
|
||||||
// Count all sessions for a user ID
|
// Count all sessions for a user ID
|
||||||
const sessionCountForUser = em
|
const sessionCountForUser = em
|
||||||
.createQueryBuilder(Session, 'session')
|
.createQueryBuilder(Session, 'session')
|
||||||
.count()
|
.count()
|
||||||
.where({ user: knex.ref('user.id') })
|
.where({ user: knex.ref('user.id') })
|
||||||
.getKnexQuery();
|
.getKnexQuery();
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const oneYearAgo = new Date();
|
const oneYearAgo = new Date();
|
||||||
oneYearAgo.setFullYear(now.getFullYear() - 1);
|
oneYearAgo.setFullYear(now.getFullYear() - 1);
|
||||||
|
|
||||||
// Delete all users who do not have any sessions AND
|
// Delete all users who do not have any sessions AND
|
||||||
// (their login date is null OR they last logged in over 1 year ago)
|
// (their login date is null OR they last logged in over 1 year ago)
|
||||||
const deletedUsers = await em
|
const deletedUsers = await em
|
||||||
.createQueryBuilder(User, 'user')
|
.createQueryBuilder(User, 'user')
|
||||||
.delete()
|
.delete()
|
||||||
.withSubQuery(sessionCountForUser, 'session.sessionCount')
|
.withSubQuery(sessionCountForUser, 'session.sessionCount')
|
||||||
.where({
|
.where({
|
||||||
'session.sessionCount': 0,
|
'session.sessionCount': 0,
|
||||||
$or: [
|
$or: [
|
||||||
{ lastLoggedIn: { $eq: undefined } },
|
{ lastLoggedIn: { $eq: undefined } },
|
||||||
{ lastLoggedIn: { $lt: oneYearAgo } },
|
{ lastLoggedIn: { $lt: oneYearAgo } },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.execute<{ affectedRows: number }>('run');
|
.execute<{ affectedRows: number }>('run');
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
`Removed ${deletedUsers.affectedRows} users older than 1 year with no sessions`,
|
`Removed ${deletedUsers.affectedRows} users older than 1 year with no sessions`,
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
42
src/modules/jobs/list/userDeletion.ts
Normal file
42
src/modules/jobs/list/userDeletion.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { Session } from '@/db/models/Session';
|
||||||
|
import { User } from '@/db/models/User';
|
||||||
|
import { job } from '@/modules/jobs/job';
|
||||||
|
|
||||||
|
// every day at 12:00:00
|
||||||
|
export const userDeletionJob = job(
|
||||||
|
'User Deletion',
|
||||||
|
'0 12 * * *',
|
||||||
|
async ({ em, log }) => {
|
||||||
|
const knex = em.getKnex();
|
||||||
|
|
||||||
|
// Count all sessions for a user ID
|
||||||
|
const sessionCountForUser = em
|
||||||
|
.createQueryBuilder(Session, 'session')
|
||||||
|
.count()
|
||||||
|
.where({ user: knex.ref('user.id') })
|
||||||
|
.getKnexQuery();
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const oneYearAgo = new Date();
|
||||||
|
oneYearAgo.setFullYear(now.getFullYear() - 1);
|
||||||
|
|
||||||
|
// Delete all users who do not have any sessions AND
|
||||||
|
// (their login date is null OR they last logged in over 1 year ago)
|
||||||
|
const deletedUsers = await em
|
||||||
|
.createQueryBuilder(User, 'user')
|
||||||
|
.delete()
|
||||||
|
.withSubQuery(sessionCountForUser, 'session.sessionCount')
|
||||||
|
.where({
|
||||||
|
'session.sessionCount': 0,
|
||||||
|
$or: [
|
||||||
|
{ lastLoggedIn: { $eq: undefined } },
|
||||||
|
{ lastLoggedIn: { $lt: oneYearAgo } },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.execute<{ affectedRows: number }>('run');
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
`Removed ${deletedUsers.affectedRows} users older than 1 year with no sessions`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
Reference in New Issue
Block a user