Skip to content

Commit ea21cc7

Browse files
feat: smarter partial update debounce (#42)
1 parent cb21f9a commit ea21cc7

File tree

7 files changed

+55
-16
lines changed

7 files changed

+55
-16
lines changed

.changeset/wet-hotels-end.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@callstack/byorg-utils': minor
3+
'@callstack/byorg-slack': patch
4+
---
5+
6+
utils: debouncePartialUpdate function for smart debounce handling

packages/slack/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
"@callstack/slack-rich-text": "workspace:*",
3535
"@slack/bolt": "^4.1.1",
3636
"@slack/web-api": "^7.8.0",
37-
"p-debounce": "^4.0.0",
3837
"ts-regex-builder": "^1.8.2"
3938
},
4039
"devDependencies": {

packages/slack/src/app.ts

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
import Slack, { LogLevel, SayFn } from '@slack/bolt';
22
import { ContextBlock, RichTextBlock, WebClient } from '@slack/web-api';
33
import { Application } from '@callstack/byorg-core';
4-
import { logger } from '@callstack/byorg-utils';
4+
import { debouncePartialUpdate, logger } from '@callstack/byorg-utils';
55
import { parseMarkdownToRichTextBlock } from '@callstack/slack-rich-text';
6-
import pDebounce from 'p-debounce';
76
import {
87
SlackMessage,
98
SlackApplicationConfig as SlackApplicationConfig,
109
ConversationMode,
1110
} from './types.js';
1211
import { fetchFileInfo, getThread } from './slack-api.js';
1312
import { formatGroupMessage, toCoreMessage } from './messages.js';
14-
import { wait } from './utils.js';
1513
import { getBotId } from './bot-id.js';
1614

1715
type MessageBlock = RichTextBlock | ContextBlock;
1816

19-
const UPDATE_THROTTLE_TIME = 1000;
17+
const MIN_UPDATE_TIME = 3000;
18+
const MIN_RESPONSE_LENGTH = 250;
2019
const NOTIFICATION_TEXT_LIMIT = 200;
2120

2221
const RESPONDING_BLOCK: MessageBlock = {
@@ -91,8 +90,6 @@ function configureSlackApp(app: Application, slack: Slack.App): void {
9190
blocks,
9291
});
9392
responseMessageTs = responseMessage.ts as string;
94-
95-
await wait(UPDATE_THROTTLE_TIME);
9693
return;
9794
}
9895

@@ -104,15 +101,17 @@ function configureSlackApp(app: Application, slack: Slack.App): void {
104101
parse: 'none',
105102
});
106103

107-
await wait(UPDATE_THROTTLE_TIME);
108104
return;
109105
};
110106

111107
let updatePartialResponsePromise: Promise<void> = Promise.resolve();
112-
const updateResponseMessageWithThrottle = pDebounce.promise(updateResponseMessage);
108+
const updateResponseMessageWithDebounce = debouncePartialUpdate(updateResponseMessage, {
109+
minUpdateTime: MIN_UPDATE_TIME,
110+
minResponseLength: MIN_RESPONSE_LENGTH,
111+
});
113112

114113
const handlePartialResponse = (response: string): void => {
115-
updatePartialResponsePromise = updateResponseMessageWithThrottle(response);
114+
updatePartialResponsePromise = updateResponseMessageWithDebounce(response);
116115
};
117116

118117
const startTime = performance.now();

packages/slack/src/utils.ts

-3
This file was deleted.

packages/utils/src/debounce.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export type PartialUpdateFn = (text: string) => Promise<void>;
2+
export type DebouncePartialUpdateOptions = {
3+
minUpdateTime: number;
4+
minResponseLength: number;
5+
};
6+
7+
export function debouncePartialUpdate(
8+
partialUpdate: PartialUpdateFn,
9+
{ minResponseLength, minUpdateTime }: DebouncePartialUpdateOptions,
10+
) {
11+
let pendingPromise: Promise<void> | undefined;
12+
let lastUpdate: number | undefined;
13+
14+
return async function (text: string) {
15+
// Wait for the last update to finish
16+
if (pendingPromise) {
17+
return pendingPromise;
18+
}
19+
20+
// Time-based debounce
21+
if (lastUpdate !== undefined && performance.now() - lastUpdate < minUpdateTime) {
22+
return;
23+
}
24+
25+
// Skip too short initial messages
26+
if (text.length < minResponseLength) {
27+
return;
28+
}
29+
30+
try {
31+
lastUpdate = performance.now();
32+
pendingPromise = partialUpdate(text);
33+
return await pendingPromise;
34+
} finally {
35+
pendingPromise = undefined;
36+
}
37+
};
38+
}

packages/utils/src/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ export type { Logger, LogLevel } from './logger/types.js';
55
export { requireEnv } from './env.js';
66

77
export { withCache } from './with-cache.js';
8+
9+
export { debouncePartialUpdate } from './debounce.js';
10+
export type { PartialUpdateFn, DebouncePartialUpdateOptions } from './debounce.js';

pnpm-lock.yaml

-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)