1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Server: Resolves #9931: Add task to delete events older than a week (#11372)

This commit is contained in:
Adrien Poupa 2024-12-09 10:48:21 -05:00 committed by GitHub
parent ceea0bc0ad
commit f5b5cf74c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 79 additions and 2 deletions

View File

@ -30,7 +30,7 @@ const defaultEnvValues: EnvVariables = {
IS_ADMIN_INSTANCE: true, IS_ADMIN_INSTANCE: true,
INSTANCE_NAME: '', INSTANCE_NAME: '',
// Maxiumm allowed drift between NTP time and server time. A few // Maximum allowed drift between NTP time and server time. A few
// milliseconds is normally not an issue unless many clients are modifying // milliseconds is normally not an issue unless many clients are modifying
// the same note at the exact same time. But past a certain limit, it might // the same note at the exact same time. But past a certain limit, it might
// mean the server clock is incorrect and should be fixed, as that could // mean the server clock is incorrect and should be fixed, as that could
@ -118,6 +118,13 @@ const defaultEnvValues: EnvVariables = {
USER_DATA_AUTO_DELETE_ENABLED: false, USER_DATA_AUTO_DELETE_ENABLED: false,
USER_DATA_AUTO_DELETE_AFTER_DAYS: 90, USER_DATA_AUTO_DELETE_AFTER_DAYS: 90,
// ==================================================
// Events deletion
// ==================================================
EVENTS_AUTO_DELETE_ENABLED: false,
EVENTS_AUTO_DELETE_AFTER_DAYS: 30,
// ================================================== // ==================================================
// LDAP configuration // LDAP configuration
// ================================================== // ==================================================
@ -210,6 +217,9 @@ export interface EnvVariables {
USER_DATA_AUTO_DELETE_ENABLED: boolean; USER_DATA_AUTO_DELETE_ENABLED: boolean;
USER_DATA_AUTO_DELETE_AFTER_DAYS: number; USER_DATA_AUTO_DELETE_AFTER_DAYS: number;
EVENTS_AUTO_DELETE_ENABLED: boolean;
EVENTS_AUTO_DELETE_AFTER_DAYS: number;
LDAP_1_ENABLED: boolean; LDAP_1_ENABLED: boolean;
LDAP_1_USER_AUTO_CREATION: boolean; LDAP_1_USER_AUTO_CREATION: boolean;
LDAP_1_HOST: string; LDAP_1_HOST: string;

View File

@ -1,6 +1,6 @@
import { EventType } from '../services/database/types'; import { EventType } from '../services/database/types';
import { beforeAllDb, afterAllTests, beforeEachDb, models } from '../utils/testing/testUtils'; import { beforeAllDb, afterAllTests, beforeEachDb, models } from '../utils/testing/testUtils';
import { msleep } from '../utils/time'; import { msleep, Week } from '../utils/time';
describe('EventModel', () => { describe('EventModel', () => {
@ -37,4 +37,52 @@ describe('EventModel', () => {
expect(latest.id).toBe(allEvents[1].id); expect(latest.id).toBe(allEvents[1].id);
}); });
test('deletion should work when there are no events', async () => {
const allEvents = (await models().event().all());
expect(allEvents.length).toBe(0);
await models().event().deleteOldEvents(Week);
const remainingEvents = (await models().event().all());
expect(remainingEvents.length).toBe(0);
});
test('should not delete recent events', async () => {
await models().event().create(EventType.TaskStarted, 'deleteExpiredTokens');
const allEvents = (await models().event().all());
expect(allEvents.length).toBe(1);
await models().event().deleteOldEvents(Week);
const remainingEvents = (await models().event().all());
expect(remainingEvents.length).toBe(1);
});
test('should delete events older than specified interval', async () => {
const now = Date.now();
const aWeekAgo = now - Week;
jest.useFakeTimers();
for (const difference of [-10, -5, 0, 5, 10]) {
jest.setSystemTime(aWeekAgo + difference);
await models().event().create(EventType.TaskStarted, 'deleteExpiredTokens');
}
const allEvents = (await models().event().all());
expect(allEvents.length).toBe(5);
jest.setSystemTime(now);
await models().event().deleteOldEvents(Week);
const remainingEvents = (await models().event().all());
expect(remainingEvents.length).toBe(3);
for (const event of remainingEvents) {
expect(event.created_time).toBeGreaterThanOrEqual(aWeekAgo);
}
jest.useRealTimers();
});
}); });

View File

@ -33,4 +33,11 @@ export default class EventModel extends BaseModel<Event> {
.first(); .first();
} }
public async deleteOldEvents(ttl: number): Promise<void> {
const cutOffDate = Date.now() - ttl;
await this.db(this.tableName)
.where('created_time', '<', cutOffDate)
.delete();
}
} }

View File

@ -32,6 +32,7 @@ export const taskIdToLabel = (taskId: TaskId): string => {
[TaskId.ProcessShares]: 'Process shared items', [TaskId.ProcessShares]: 'Process shared items',
[TaskId.ProcessEmails]: 'Process emails', [TaskId.ProcessEmails]: 'Process emails',
[TaskId.LogHeartbeatMessage]: 'Log heartbeat message', [TaskId.LogHeartbeatMessage]: 'Log heartbeat message',
[TaskId.DeleteOldEvents]: 'Delete old events',
}; };
const s = strings[taskId]; const s = strings[taskId];

View File

@ -136,6 +136,7 @@ export enum TaskId {
ProcessShares, ProcessShares,
ProcessEmails, ProcessEmails,
LogHeartbeatMessage, LogHeartbeatMessage,
DeleteOldEvents,
} }
// AUTO-GENERATED-TYPES // AUTO-GENERATED-TYPES

View File

@ -4,6 +4,7 @@ import TaskService, { Task, taskIdToLabel } from '../services/TaskService';
import { Services } from '../services/types'; import { Services } from '../services/types';
import { logHeartbeat as logHeartbeatMessage } from './metrics'; import { logHeartbeat as logHeartbeatMessage } from './metrics';
import { Config, Env } from './types'; import { Config, Env } from './types';
import { Day } from './time';
export default async function(env: Env, models: Models, config: Config, services: Services): Promise<TaskService> { export default async function(env: Env, models: Models, config: Config, services: Services): Promise<TaskService> {
const taskService = new TaskService(env, models, config, services); const taskService = new TaskService(env, models, config, services);
@ -93,6 +94,15 @@ export default async function(env: Env, models: Models, config: Config, services
}); });
} }
if (config.EVENTS_AUTO_DELETE_ENABLED) {
tasks.push({
id: TaskId.DeleteOldEvents,
description: taskIdToLabel(TaskId.DeleteOldEvents),
schedule: '0 0 * * *',
run: (models: Models) => models.event().deleteOldEvents(config.EVENTS_AUTO_DELETE_AFTER_DAYS * Day),
});
}
if (config.isJoplinCloud) { if (config.isJoplinCloud) {
tasks = tasks.concat([ tasks = tasks.concat([
{ {