diff --git a/src/activitypub/index.js b/src/activitypub/index.js index 7dab8ad6ba..b3ae1e83a1 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -8,6 +8,7 @@ const request = require('../request'); const db = require('../database'); const meta = require('../meta'); const categories = require('../categories'); +const topics = require('../topics'); const posts = require('../posts'); const messaging = require('../messaging'); const user = require('../user'); @@ -512,7 +513,7 @@ ActivityPub.buildRecipients = async function (object, { pid, uid, cid }) { // Topic posters, post announcers and their followers if (pid) { const tid = await posts.getPostField(pid, 'tid'); - const participants = (await db.getSortedSetMembers(`tid:${tid}:posters`)) + const participants = (await topics.getUids(tid)) .filter(uid => !utils.isNumber(uid)); // remote users only const announcers = (await ActivityPub.notes.announce.list({ pid })).map(({ actor }) => actor); const auxiliaries = Array.from(new Set([...participants, ...announcers])); diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index b353bbaaa5..3cef55670e 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -635,6 +635,12 @@ Notes.backfill = async (pids) => { Notes.announce = {}; +Notes.announce._cache = ttlCache({ + name: 'ap-note-announce-cache', + max: 500, + ttl: 1000 * 60 * 60, // 1 hour +}); + Notes.announce.list = async ({ pid, tid }) => { let pids = []; if (pid) { @@ -652,8 +658,24 @@ Notes.announce.list = async ({ pid, tid }) => { return []; } - const keys = pids.map(pid => `pid:${pid}:announces`); - let announces = await db.getSortedSetsMembersWithScores(keys); + const missing = []; + let announces = pids.map((pid, idx) => { + const cached = Notes.announce._cache.get(pid); + if (!cached) { + missing.push(idx); + } + return cached; + }); + + if (missing.length) { + const toCache = await db.getSortedSetsMembersWithScores(missing.map(idx => `pid:${pids[idx]}:announces`)); + toCache.forEach((value, idx) => { + const pid = pids[missing[idx]]; + Notes.announce._cache.set(pid, value); + announces[missing[idx]] = value; + }); + } + announces = announces.reduce((memo, cur, idx) => { if (cur.length) { const pid = pids[idx]; @@ -672,6 +694,7 @@ Notes.announce.add = async (pid, actor, timestamp = Date.now()) => { posts.getPostField(pid, 'tid'), db.sortedSetAdd(`pid:${pid}:announces`, timestamp, actor), ]); + Notes.announce._cache.del(`pid:${pid}:announces`); await Promise.all([ posts.setPostField(pid, 'announces', await db.sortedSetCard(`pid:${pid}:announces`)), topics.tools.share(tid, actor, timestamp), @@ -680,6 +703,8 @@ Notes.announce.add = async (pid, actor, timestamp = Date.now()) => { Notes.announce.remove = async (pid, actor) => { await db.sortedSetRemove(`pid:${pid}:announces`, actor); + Notes.announce._cache.del(`pid:${pid}:announces`); + const count = await db.sortedSetCard(`pid:${pid}:announces`); if (count > 0) { await posts.setPostField(pid, 'announces', count); @@ -693,6 +718,7 @@ Notes.announce.removeAll = async (pid) => { db.delete(`pid:${pid}:announces`), db.deleteObjectField(`post:${pid}`, 'announces'), ]); + Notes.announce._cache.del(`pid:${pid}:announces`); }; Notes.delete = async (pids) => { diff --git a/src/topics/user.js b/src/topics/user.js index 7a2265512c..f7d13f50ea 100644 --- a/src/topics/user.js +++ b/src/topics/user.js @@ -2,6 +2,7 @@ const db = require('../database'); const utils = require('../utils'); +const cache = require('../cache'); module.exports = function (Topics) { Topics.isOwner = async function (tid, uid) { @@ -13,6 +14,13 @@ module.exports = function (Topics) { }; Topics.getUids = async function (tid) { - return await db.getSortedSetRevRangeByScore(`tid:${tid}:posters`, 0, -1, '+inf', 1); + const cacheKey = `tid:${tid}:uids`; + let posters = cache.get(cacheKey, tid); + if (!posters) { + posters = await db.getSortedSetRevRangeByScore(`tid:${tid}:posters`, 0, -1, '+inf', 1); + cache.set(cacheKey, posters); + } + + return posters; }; };