2020-06-02 00:26:06 +03:00
|
|
|
import moment from "moment-timezone";
|
2023-07-01 12:17:45 +00:00
|
|
|
import { In } from "typeorm";
|
2021-11-02 20:08:54 +02:00
|
|
|
import { DAYS, DBDateFormat, MINUTES, SECONDS, sleep } from "../../utils";
|
2023-07-01 12:17:45 +00:00
|
|
|
import { dataSource } from "../dataSource";
|
2021-06-06 23:51:32 +02:00
|
|
|
import { SavedMessage } from "../entities/SavedMessage";
|
2020-06-02 00:26:06 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* How long message edits, deletions, etc. will include the original message content.
|
|
|
|
* This is very heavy storage-wise, so keeping it as low as possible is ideal.
|
|
|
|
*/
|
|
|
|
const RETENTION_PERIOD = 1 * DAYS;
|
|
|
|
const BOT_MESSAGE_RETENTION_PERIOD = 30 * MINUTES;
|
|
|
|
const DELETED_MESSAGE_RETENTION_PERIOD = 5 * MINUTES;
|
2021-11-02 20:08:54 +02:00
|
|
|
const CLEAN_PER_LOOP = 100;
|
2020-06-02 00:26:06 +03:00
|
|
|
|
|
|
|
export async function cleanupMessages(): Promise<number> {
|
|
|
|
let cleaned = 0;
|
|
|
|
|
2023-07-01 12:17:45 +00:00
|
|
|
const messagesRepository = dataSource.getRepository(SavedMessage);
|
2020-06-02 00:26:06 +03:00
|
|
|
|
2021-09-11 19:06:51 +03:00
|
|
|
const deletedAtThreshold = moment.utc().subtract(DELETED_MESSAGE_RETENTION_PERIOD, "ms").format(DBDateFormat);
|
|
|
|
const postedAtThreshold = moment.utc().subtract(RETENTION_PERIOD, "ms").format(DBDateFormat);
|
|
|
|
const botPostedAtThreshold = moment.utc().subtract(BOT_MESSAGE_RETENTION_PERIOD, "ms").format(DBDateFormat);
|
2020-06-02 00:26:06 +03:00
|
|
|
|
|
|
|
// SELECT + DELETE messages in batches
|
|
|
|
// This is to avoid deadlocks that happened frequently when deleting with the same criteria as the select below
|
|
|
|
// when a message was being inserted at the same time
|
2021-09-12 22:09:29 +03:00
|
|
|
let ids: string[];
|
2020-06-02 00:26:06 +03:00
|
|
|
do {
|
2023-07-01 12:17:45 +00:00
|
|
|
const deletedMessageRows = await dataSource.query(
|
2020-06-02 00:26:06 +03:00
|
|
|
`
|
|
|
|
SELECT id
|
|
|
|
FROM messages
|
|
|
|
WHERE (
|
2021-09-12 22:09:29 +03:00
|
|
|
deleted_at IS NOT NULL
|
|
|
|
AND deleted_at <= ?
|
|
|
|
)
|
2020-06-02 00:26:06 +03:00
|
|
|
LIMIT ${CLEAN_PER_LOOP}
|
|
|
|
`,
|
2021-09-12 22:09:29 +03:00
|
|
|
[deletedAtThreshold],
|
2020-06-02 00:26:06 +03:00
|
|
|
);
|
|
|
|
|
2023-07-01 12:17:45 +00:00
|
|
|
const oldPostedRows = await dataSource.query(
|
2021-09-12 22:09:29 +03:00
|
|
|
`
|
|
|
|
SELECT id
|
|
|
|
FROM messages
|
|
|
|
WHERE (
|
|
|
|
posted_at <= ?
|
|
|
|
AND is_permanent = 0
|
|
|
|
)
|
|
|
|
LIMIT ${CLEAN_PER_LOOP}
|
|
|
|
`,
|
|
|
|
[postedAtThreshold],
|
|
|
|
);
|
|
|
|
|
2023-07-01 12:17:45 +00:00
|
|
|
const oldBotPostedRows = await dataSource.query(
|
2021-09-12 22:09:29 +03:00
|
|
|
`
|
|
|
|
SELECT id
|
|
|
|
FROM messages
|
|
|
|
WHERE (
|
|
|
|
is_bot = 1
|
|
|
|
AND posted_at <= ?
|
|
|
|
AND is_permanent = 0
|
|
|
|
)
|
|
|
|
LIMIT ${CLEAN_PER_LOOP}
|
|
|
|
`,
|
|
|
|
[botPostedAtThreshold],
|
|
|
|
);
|
|
|
|
|
|
|
|
ids = Array.from(
|
|
|
|
new Set([
|
|
|
|
...deletedMessageRows.map((r) => r.id),
|
|
|
|
...oldPostedRows.map((r) => r.id),
|
|
|
|
...oldBotPostedRows.map((r) => r.id),
|
|
|
|
]),
|
|
|
|
);
|
|
|
|
|
|
|
|
if (ids.length > 0) {
|
2020-06-02 00:26:06 +03:00
|
|
|
await messagesRepository.delete({
|
2021-09-12 22:09:29 +03:00
|
|
|
id: In(ids),
|
2020-06-02 00:26:06 +03:00
|
|
|
});
|
2021-11-02 20:08:54 +02:00
|
|
|
await sleep(1 * SECONDS);
|
2020-06-02 00:26:06 +03:00
|
|
|
}
|
|
|
|
|
2021-09-12 22:09:29 +03:00
|
|
|
cleaned += ids.length;
|
|
|
|
} while (ids.length > 0);
|
2020-06-02 00:26:06 +03:00
|
|
|
|
|
|
|
return cleaned;
|
|
|
|
}
|