Clean up Actor cache

This commit is contained in:
Bryan Ashby 2023-02-08 17:19:12 -07:00
parent c5f0e0e6ef
commit 9b08cf827b
No known key found for this signature in database
GPG Key ID: C2C1B501E4EFD994
2 changed files with 54 additions and 22 deletions

View File

@ -13,6 +13,7 @@ const ActivityPubSettings = require('./settings');
const ActivityPubObject = require('./object'); const ActivityPubObject = require('./object');
const { ActivityStreamMediaType } = require('./const'); const { ActivityStreamMediaType } = require('./const');
const apDb = require('../database').dbs.activitypub; const apDb = require('../database').dbs.activitypub;
const Config = require('../config').get;
// deps // deps
const _ = require('lodash'); const _ = require('lodash');
@ -22,7 +23,8 @@ const { getISOTimestampString } = require('../database.js');
const moment = require('moment'); const moment = require('moment');
const paths = require('path'); const paths = require('path');
const ActorCacheTTL = moment.duration(120, 'days'); const ActorCacheExpiration = moment.duration(15, 'days');
const ActorCacheMaxAgeDays = 125; // hasn't been used in >= 125 days, nuke it.
// default context for Actor's // default context for Actor's
const DefaultContext = ActivityPubObject.makeContext(['https://w3id.org/security/v1'], { const DefaultContext = ActivityPubObject.makeContext(['https://w3id.org/security/v1'], {
@ -157,16 +159,28 @@ module.exports = class Actor extends ActivityPubObject {
} }
static fromId(id, cb) { static fromId(id, cb) {
Actor._fromCache(id, (err, actor, subject) => { let delivered = false;
const callback = (e, a, s) => {
if (!delivered) {
delivered = true;
return cb(e, a, s);
}
};
Actor._fromCache(id, (err, actor, subject, needsRefresh) => {
if (!err) { if (!err) {
// cache hit // cache hit
return cb(null, actor, subject); callback(null, actor, subject);
if (!needsRefresh) {
return;
}
} }
// cache miss: attempt to fetch & populate // Cache miss or needs refreshed; Try to do so now
Actor._fromWebFinger(id, (err, actor, subject) => { Actor._fromWebFinger(id, (err, actor, subject) => {
if (err) { if (err) {
return cb(err); return callback(err);
} }
if (subject) { if (subject) {
@ -176,7 +190,7 @@ module.exports = class Actor extends ActivityPubObject {
} }
// deliver result to caller // deliver result to caller
cb(err, actor, subject); callback(err, actor, subject);
// cache our entry // cache our entry
if (actor) { if (actor) {
@ -195,6 +209,28 @@ module.exports = class Actor extends ActivityPubObject {
}); });
} }
static actorCacheMaintenanceTask(args, cb) {
const enabled = _.get(
Config(),
'contentServers.web.handlers.activityPub.enabled'
);
if (!enabled) {
return;
}
apDb.run(
`DELETE FROM actor_cache
WHERE DATETIME(timestamp) > DATETIME("now", "+${ActorCacheMaxAgeDays}");`,
err => {
if (err) {
// :TODO: log me
}
return cb(null); // always non-fatal
}
);
}
static _fromRemoteQuery(id, cb) { static _fromRemoteQuery(id, cb) {
const headers = { const headers = {
Accept: ActivityStreamMediaType, Accept: ActivityStreamMediaType,
@ -215,13 +251,13 @@ module.exports = class Actor extends ActivityPubObject {
}); });
} }
static _fromCache(id, cb) { static _fromCache(actorIdOrSubject, cb) {
apDb.get( apDb.get(
`SELECT rowid, actor_json, subject, timestamp, `SELECT rowid, actor_json, subject, timestamp,
FROM actor_cache FROM actor_cache
WHERE actor_id = ? OR subject = ? WHERE actor_id = ? OR subject = ?
LIMIT 1;`, LIMIT 1;`,
[id, id], [actorIdOrSubject, actorIdOrSubject],
(err, row) => { (err, row) => {
if (err) { if (err) {
return cb(err); return cb(err);
@ -232,19 +268,9 @@ module.exports = class Actor extends ActivityPubObject {
} }
const timestamp = moment(row.timestamp); const timestamp = moment(row.timestamp);
if (moment().isAfter(timestamp.add(ActorCacheTTL))) { const needsRefresh = moment().isAfter(
apDb.run( timestamp.add(ActorCacheExpiration)
`DELETE FROM actor_cache );
WHERE rowid = ?;`,
[row.rowid],
err => {
if (err) {
// :TODO: Log me
}
return cb(Errors.Expired('The cache entry is expired'));
}
);
}
const obj = ActivityPubObject.fromJsonString(row.actor_json); const obj = ActivityPubObject.fromJsonString(row.actor_json);
if (!obj || !obj.isValid()) { if (!obj || !obj.isValid()) {
@ -257,7 +283,7 @@ module.exports = class Actor extends ActivityPubObject {
} }
const subject = row.subject || actor.id; const subject = row.subject || actor.id;
return cb(null, actor, subject); return cb(null, actor, subject, needsRefresh);
} }
); );
} }

View File

@ -1082,6 +1082,12 @@ module.exports = () => {
], ],
}, },
// Removes old Actor records
activityPubActorCacheMaintenance: {
schedule: 'every 24 hours',
action: '@method:/core/activitypub/actor.js:actorCacheMaintenanceTask',
},
// //
// Enable the following entry in your config.hjson to periodically create/update // Enable the following entry in your config.hjson to periodically create/update
// DESCRIPT.ION files for your file base // DESCRIPT.ION files for your file base