
























@@ -31,6 +31,7 @@ const SLACK_UPLOAD_SSRF_POLICY = {
3131};
3232const SLACK_DM_CHANNEL_CACHE_MAX = 1024;
3333const slackDmChannelCache = new Map<string, string>();
34+const slackSendQueues = new Map<string, Promise<void>>();
34353536type SlackRecipient =
3637| {
@@ -179,6 +180,36 @@ function parseRecipient(raw: string): SlackRecipient {
179180return { kind: target.kind, id: target.id };
180181}
181182183+function createSlackSendQueueKey(params: {
184+accountId: string;
185+token: string;
186+recipient: SlackRecipient;
187+threadTs?: string;
188+}): string {
189+const isUserId = params.recipient.kind === "user" || /^U[A-Z0-9]+$/i.test(params.recipient.id);
190+const recipientKey = `${isUserId ? "user" : params.recipient.kind}:${params.recipient.id}`;
191+return `${params.accountId}:${params.token}:${recipientKey}:${params.threadTs ?? ""}`;
192+}
193+194+async function runQueuedSlackSend<T>(key: string, task: () => Promise<T>): Promise<T> {
195+const previous = slackSendQueues.get(key) ?? Promise.resolve();
196+let releaseCurrent!: () => void;
197+const current = new Promise<void>((resolve) => {
198+releaseCurrent = resolve;
199+});
200+const queuedCurrent = previous.catch(() => undefined).then(() => current);
201+slackSendQueues.set(key, queuedCurrent);
202+await previous.catch(() => undefined);
203+try {
204+return await task();
205+} finally {
206+releaseCurrent();
207+if (slackSendQueues.get(key) === queuedCurrent) {
208+slackSendQueues.delete(key);
209+}
210+}
211+}
212+182213function createSlackDmCacheKey(params: {
183214accountId?: string;
184215token: string;
@@ -236,6 +267,10 @@ export function clearSlackDmChannelCache(): void {
236267slackDmChannelCache.clear();
237268}
238269270+export function clearSlackSendQueuesForTest(): void {
271+slackSendQueues.clear();
272+}
273+239274async function uploadSlackFile(params: {
240275client: WebClient;
241276channelId: string;
@@ -332,8 +367,37 @@ export async function sendMessageSlack(
332367fallbackToken: account.botToken,
333368fallbackSource: account.botTokenSource,
334369});
335-const client = opts.client ?? createSlackWriteClient(token);
336370const recipient = parseRecipient(to);
371+const queueKey = createSlackSendQueueKey({
372+accountId: account.accountId,
373+ token,
374+ recipient,
375+threadTs: opts.threadTs,
376+});
377+return await runQueuedSlackSend(queueKey, () =>
378+sendMessageSlackQueued({
379+ trimmedMessage,
380+ opts,
381+ cfg,
382+ account,
383+ token,
384+ recipient,
385+ blocks,
386+}),
387+);
388+}
389+390+async function sendMessageSlackQueued(params: {
391+trimmedMessage: string;
392+opts: SlackSendOpts;
393+cfg: OpenClawConfig;
394+account: ReturnType<typeof resolveSlackAccount>;
395+token: string;
396+recipient: SlackRecipient;
397+blocks?: (Block | KnownBlock)[];
398+}): Promise<SlackSendResult> {
399+const { opts, cfg, account, token, recipient, blocks, trimmedMessage } = params;
400+const client = opts.client ?? createSlackWriteClient(token);
337401const { channelId } = await resolveChannelId(client, recipient, {
338402accountId: account.accountId,
339403 token,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。