perf(main): refresh message feed cache in background
This commit is contained in:
parent
6bb8d87bc7
commit
9c29b0f8f1
2 changed files with 61 additions and 4 deletions
|
|
@ -449,6 +449,14 @@ export class TeamMessageFeedService {
|
||||||
messages: cached.messages,
|
messages: cached.messages,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (cached && !cacheDirty && cacheExpired) {
|
||||||
|
this.refreshCleanExpiredCacheInBackground(teamName, cached, now);
|
||||||
|
return {
|
||||||
|
teamName,
|
||||||
|
feedRevision: cached.feedRevision,
|
||||||
|
messages: cached.messages,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const existingRequest = this.inFlightByTeam.get(teamName);
|
const existingRequest = this.inFlightByTeam.get(teamName);
|
||||||
const generationAtStart = this.getGeneration(teamName);
|
const generationAtStart = this.getGeneration(teamName);
|
||||||
|
|
@ -479,6 +487,43 @@ export class TeamMessageFeedService {
|
||||||
return this.generationByTeam.get(teamName) ?? 0;
|
return this.generationByTeam.get(teamName) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private refreshCleanExpiredCacheInBackground(
|
||||||
|
teamName: string,
|
||||||
|
cached: TeamMessageFeedCacheEntry,
|
||||||
|
now: number
|
||||||
|
): void {
|
||||||
|
const generationAtStart = this.getGeneration(teamName);
|
||||||
|
const existingRequest = this.inFlightByTeam.get(teamName);
|
||||||
|
if (existingRequest?.generationAtStart === generationAtStart) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = this.buildFeed(teamName, cached, now, false, true, generationAtStart).catch(
|
||||||
|
(error) => {
|
||||||
|
logger.debug(
|
||||||
|
`[${teamName}] background message feed refresh failed: ${
|
||||||
|
error instanceof Error ? error.message : String(error)
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
teamName,
|
||||||
|
feedRevision: cached.feedRevision,
|
||||||
|
messages: cached.messages,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const trackedRequest = request.finally(() => {
|
||||||
|
if (this.inFlightByTeam.get(teamName)?.promise === trackedRequest) {
|
||||||
|
this.inFlightByTeam.delete(teamName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.inFlightByTeam.set(teamName, {
|
||||||
|
promise: trackedRequest,
|
||||||
|
generationAtStart,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async buildFeed(
|
private async buildFeed(
|
||||||
teamName: string,
|
teamName: string,
|
||||||
cached: TeamMessageFeedCacheEntry | undefined,
|
cached: TeamMessageFeedCacheEntry | undefined,
|
||||||
|
|
|
||||||
|
|
@ -167,9 +167,12 @@ Messages:
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('refreshes the durable feed after cache expiry even when the dirty signal was missed', async () => {
|
it('returns clean expired cache immediately and refreshes durable feed in the background', async () => {
|
||||||
let inboxMessages: InboxMessage[] = [makeMessage()];
|
const refreshRequest = createDeferred<InboxMessage[]>();
|
||||||
const getInboxMessages = vi.fn(async () => inboxMessages);
|
const getInboxMessages = vi
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce([makeMessage()])
|
||||||
|
.mockImplementationOnce(() => refreshRequest.promise);
|
||||||
const service = new TeamMessageFeedService({
|
const service = new TeamMessageFeedService({
|
||||||
getConfig: vi.fn(async () => config),
|
getConfig: vi.fn(async () => config),
|
||||||
getInboxMessages,
|
getInboxMessages,
|
||||||
|
|
@ -179,7 +182,7 @@ Messages:
|
||||||
|
|
||||||
await service.getFeed('signal-ops-4');
|
await service.getFeed('signal-ops-4');
|
||||||
|
|
||||||
inboxMessages = [
|
const refreshedMessages = [
|
||||||
makeMessage({
|
makeMessage({
|
||||||
from: 'jack',
|
from: 'jack',
|
||||||
to: 'user',
|
to: 'user',
|
||||||
|
|
@ -192,6 +195,15 @@ Messages:
|
||||||
|
|
||||||
vi.setSystemTime(new Date('2026-04-19T18:46:46.500Z'));
|
vi.setSystemTime(new Date('2026-04-19T18:46:46.500Z'));
|
||||||
|
|
||||||
|
const stale = await service.getFeed('signal-ops-4');
|
||||||
|
expect(getInboxMessages).toHaveBeenCalledTimes(2);
|
||||||
|
expect(stale.messages).toHaveLength(1);
|
||||||
|
|
||||||
|
refreshRequest.resolve(refreshedMessages);
|
||||||
|
await refreshRequest.promise;
|
||||||
|
await Promise.resolve();
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
const refreshed = await service.getFeed('signal-ops-4');
|
const refreshed = await service.getFeed('signal-ops-4');
|
||||||
expect(getInboxMessages).toHaveBeenCalledTimes(2);
|
expect(getInboxMessages).toHaveBeenCalledTimes(2);
|
||||||
expect(
|
expect(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue