Split user deletion job and add more job logs

This commit is contained in:
William Oldham
2023-11-04 12:30:04 +00:00
parent 04175fafae
commit 4b79a43e15
5 changed files with 111 additions and 51 deletions

View File

@@ -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();
} }

View File

@@ -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);
} }
}, },

View File

@@ -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();
},
);

View File

@@ -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`,
); );
}); },
);

View 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`,
);
},
);