fix(cache): call JSON.stringify when storing value in cache.tryGet (#20671)

* fix(cache): call JSON.stringify when storing value in cache.tryGet

The value is returned as-is, so we may assume that it's not JSON
stringified inside `getValueFunc`. Otherwise, the caller already needs
to distinguish between values that are either JSON parsed or not.

* Revert "fix(routes/mastodon): don't refresh account ID cache (#20663)"

This reverts commit c2cff410fa.

* test: add test

* test: lint
This commit is contained in:
Yufan You 2026-05-07 01:26:11 +08:00 committed by GitHub
parent ae48d4cfd1
commit 5589b89478
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 42 additions and 29 deletions

View File

@ -103,37 +103,32 @@ async function getAccountIdByAcct(acct) {
const search_url = `https://${site}/api/v2/search`;
const cacheUid = `mastodon_acct_id/${site}/${acct}`;
const account_id = await cache.tryGet(
cacheUid,
async () => {
const search_response = await got({
method: 'get',
url: search_url,
headers: apiHeaders(site),
searchParams: {
q: acct,
type: 'accounts',
},
});
const [acctUser, acctHost] = acct.split('@').filter(Boolean);
let acctOnServer;
const account_id = await cache.tryGet(cacheUid, async () => {
const search_response = await got({
method: 'get',
url: search_url,
headers: apiHeaders(site),
searchParams: {
q: acct,
type: 'accounts',
},
});
const [acctUser, acctHost] = acct.split('@').filter(Boolean);
let acctOnServer;
if (acctHost) {
acctOnServer = acctHost === acctDomain ? acctUser : acctUser + '@' + acctHost;
} else {
acctOnServer = acctUser;
}
if (acctHost) {
acctOnServer = acctHost === acctDomain ? acctUser : acctUser + '@' + acctHost;
} else {
acctOnServer = acctUser;
}
const accountData = search_response.data.accounts.filter((item) => item.acct === acctOnServer);
const accountData = search_response.data.accounts.filter((item) => item.acct === acctOnServer);
if (accountData.length === 0) {
throw new Error(`acct ${acct} not found`);
}
return accountData[0].id;
},
config.cache.contentExpire,
false
);
if (accountData.length === 0) {
throw new Error(`acct ${acct} not found`);
}
return accountData[0].id;
});
return { site, account_id };
}

View File

@ -42,6 +42,24 @@ describe('cache', () => {
expect(await memory.has('missing')).toBe(false);
});
it('tryGet preserves snowflake ID precision', async () => {
process.env.CACHE_TYPE = 'memory';
const cache = (await import('@/utils/cache')).default;
if (!cache.clients.memoryCache || !cache.status.available) {
throw new Error('Memory cache client error');
}
const snowflakeId = '1234567890123456789';
const fetcher = vi.fn(() => Promise.resolve(snowflakeId));
const fresh = await cache.tryGet('snowflake', fetcher);
expect(fresh).toBe(snowflakeId);
const cached = await cache.tryGet('snowflake', fetcher);
expect(typeof cached).toBe('string');
expect(cached).toBe(snowflakeId);
expect(fetcher).toHaveBeenCalledTimes(1);
});
it('redis', async () => {
process.env.CACHE_TYPE = 'redis';
const cache = (await import('@/utils/cache')).default;

View File

@ -141,7 +141,7 @@ export default {
return v as T;
} else {
const value = await getValueFunc();
cacheModule.set(key, value, maxAge);
cacheModule.set(key, JSON.stringify(value), maxAge);
return value;
}