mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 15:59:30 +00:00
fix(slack): bound conversation info cache (#101562)
This commit is contained in:
parent
407443264c
commit
4e29b2f5ab
2 changed files with 76 additions and 7 deletions
|
|
@ -178,6 +178,55 @@ describe("resolveSlackChannelType", () => {
|
|||
expect(conversationsInfoMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("evicts least-recently-used conversation info entries after the cache limit", async () => {
|
||||
const cacheMaxEntries = 1024;
|
||||
const cfg = {
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-test",
|
||||
},
|
||||
},
|
||||
} as never;
|
||||
|
||||
conversationsInfoMock.mockImplementation(async ({ channel }) => ({
|
||||
channel: {
|
||||
id: channel,
|
||||
},
|
||||
}));
|
||||
|
||||
for (let index = 0; index < cacheMaxEntries; index++) {
|
||||
await resolveSlackConversationInfo({
|
||||
cfg,
|
||||
channelId: `C${index.toString().padStart(8, "0")}`,
|
||||
});
|
||||
}
|
||||
expect(conversationsInfoMock).toHaveBeenCalledTimes(cacheMaxEntries);
|
||||
|
||||
await resolveSlackConversationInfo({
|
||||
cfg,
|
||||
channelId: "C00000000",
|
||||
});
|
||||
expect(conversationsInfoMock).toHaveBeenCalledTimes(cacheMaxEntries);
|
||||
|
||||
await resolveSlackConversationInfo({
|
||||
cfg,
|
||||
channelId: `C${cacheMaxEntries.toString().padStart(8, "0")}`,
|
||||
});
|
||||
expect(conversationsInfoMock).toHaveBeenCalledTimes(cacheMaxEntries + 1);
|
||||
|
||||
await resolveSlackConversationInfo({
|
||||
cfg,
|
||||
channelId: "C00000001",
|
||||
});
|
||||
expect(conversationsInfoMock).toHaveBeenCalledTimes(cacheMaxEntries + 2);
|
||||
|
||||
await resolveSlackConversationInfo({
|
||||
cfg,
|
||||
channelId: "C00000000",
|
||||
});
|
||||
expect(conversationsInfoMock).toHaveBeenCalledTimes(cacheMaxEntries + 2);
|
||||
});
|
||||
|
||||
it("preserves the channel-type wrapper contract", async () => {
|
||||
conversationsInfoMock.mockResolvedValueOnce({
|
||||
channel: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// Slack plugin module implements channel type behavior.
|
||||
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
|
|
@ -13,8 +14,27 @@ export type SlackConversationInfo = {
|
|||
user?: string;
|
||||
};
|
||||
|
||||
const SLACK_CONVERSATION_INFO_CACHE_MAX_ENTRIES = 1024;
|
||||
const SLACK_CONVERSATION_INFO_CACHE = new Map<string, SlackConversationInfo>();
|
||||
|
||||
function getCachedSlackConversationInfo(cacheKey: string): SlackConversationInfo | undefined {
|
||||
const cached = SLACK_CONVERSATION_INFO_CACHE.get(cacheKey);
|
||||
if (cached) {
|
||||
SLACK_CONVERSATION_INFO_CACHE.delete(cacheKey);
|
||||
SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, cached);
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
function setCachedSlackConversationInfo(
|
||||
cacheKey: string,
|
||||
conversationInfo: SlackConversationInfo,
|
||||
): void {
|
||||
SLACK_CONVERSATION_INFO_CACHE.delete(cacheKey);
|
||||
SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, conversationInfo);
|
||||
pruneMapToMaxSize(SLACK_CONVERSATION_INFO_CACHE, SLACK_CONVERSATION_INFO_CACHE_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
export async function resolveSlackConversationInfo(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
|
|
@ -26,7 +46,7 @@ export async function resolveSlackConversationInfo(params: {
|
|||
}
|
||||
const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId });
|
||||
const cacheKey = `${account.accountId}:${channelId}`;
|
||||
const cached = SLACK_CONVERSATION_INFO_CACHE.get(cacheKey);
|
||||
const cached = getCachedSlackConversationInfo(cacheKey);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
|
@ -42,7 +62,7 @@ export async function resolveSlackConversationInfo(params: {
|
|||
groupChannels.includes(`mpim:${channelIdLower}`))
|
||||
) {
|
||||
const result = { type: "group" } as const;
|
||||
SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
|
||||
setCachedSlackConversationInfo(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +79,7 @@ export async function resolveSlackConversationInfo(params: {
|
|||
})
|
||||
) {
|
||||
const result = { type: "channel" } as const;
|
||||
SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
|
||||
setCachedSlackConversationInfo(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +90,7 @@ export async function resolveSlackConversationInfo(params: {
|
|||
if (!token) {
|
||||
const result = { type: isNativeImChannel ? "dm" : "unknown" } as const;
|
||||
if (!isNativeImChannel) {
|
||||
SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
|
||||
setCachedSlackConversationInfo(cacheKey, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -89,7 +109,7 @@ export async function resolveSlackConversationInfo(params: {
|
|||
: undefined;
|
||||
const result: SlackConversationInfo = user ? { type: "dm", user } : { type: "dm" };
|
||||
if (user) {
|
||||
SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
|
||||
setCachedSlackConversationInfo(cacheKey, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -97,12 +117,12 @@ export async function resolveSlackConversationInfo(params: {
|
|||
const channel = info.channel as { is_im?: boolean; is_mpim?: boolean } | undefined;
|
||||
const type = channel?.is_im ? "dm" : channel?.is_mpim ? "group" : "channel";
|
||||
const result = { type } as const;
|
||||
SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
|
||||
setCachedSlackConversationInfo(cacheKey, result);
|
||||
return result;
|
||||
} catch {
|
||||
const result = { type: isNativeImChannel ? "dm" : "unknown" } as const;
|
||||
if (!isNativeImChannel) {
|
||||
SLACK_CONVERSATION_INFO_CACHE.set(cacheKey, result);
|
||||
setCachedSlackConversationInfo(cacheKey, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue