feat(cache): add persistent smartdata-backed cache with LocalTsmDb, cache cleaner, and DcRouter integration

This commit is contained in:
2026-02-10 11:22:15 +00:00
parent f3f1f58b67
commit 41fe7a8a47
15 changed files with 282 additions and 39 deletions

View File

@@ -98,24 +98,20 @@ export class CacheCleaner {
const results: { collection: string; deleted: number }[] = [];
try {
// Clean CachedEmail documents
const emailsDeleted = await this.cleanCollection(CachedEmail, now);
// Clean each collection using smartdata's getInstances + delete pattern
const emailsDeleted = await this.cleanExpiredDocuments(CachedEmail, now);
results.push({ collection: 'CachedEmail', deleted: emailsDeleted });
// Clean CachedIPReputation documents
const ipReputationDeleted = await this.cleanCollection(CachedIPReputation, now);
const ipReputationDeleted = await this.cleanExpiredDocuments(CachedIPReputation, now);
results.push({ collection: 'CachedIPReputation', deleted: ipReputationDeleted });
// Clean CachedBounce documents
const bouncesDeleted = await this.cleanCollection(CachedBounce, now);
const bouncesDeleted = await this.cleanExpiredDocuments(CachedBounce, now);
results.push({ collection: 'CachedBounce', deleted: bouncesDeleted });
// Clean CachedSuppression documents (but not permanent ones)
const suppressionDeleted = await this.cleanCollection(CachedSuppression, now);
const suppressionDeleted = await this.cleanExpiredDocuments(CachedSuppression, now);
results.push({ collection: 'CachedSuppression', deleted: suppressionDeleted });
// Clean CachedDKIMKey documents
const dkimDeleted = await this.cleanCollection(CachedDKIMKey, now);
const dkimDeleted = await this.cleanExpiredDocuments(CachedDKIMKey, now);
results.push({ collection: 'CachedDKIMKey', deleted: dkimDeleted });
// Log results
@@ -137,17 +133,30 @@ export class CacheCleaner {
}
/**
* Clean expired documents from a specific collection
* Clean expired documents from a specific collection using smartdata API
*/
private async cleanCollection<T>(
documentClass: { deleteMany: (filter: any) => Promise<any> },
private async cleanExpiredDocuments<T extends { delete: () => Promise<void> }>(
documentClass: { getInstances: (filter: any) => Promise<T[]> },
now: Date
): Promise<number> {
try {
const result = await documentClass.deleteMany({
// Find all expired documents
const expiredDocs = await documentClass.getInstances({
expiresAt: { $lt: now },
});
return result?.deletedCount || 0;
// Delete each expired document
let deletedCount = 0;
for (const doc of expiredDocs) {
try {
await doc.delete();
deletedCount++;
} catch (deleteError) {
logger.log('warn', `Failed to delete expired document: ${deleteError.message}`);
}
}
return deletedCount;
} catch (error) {
logger.log('error', `Error cleaning collection: ${error.message}`);
return 0;