Skip to content

Commit fd983af

Browse files
authored
Merge pull request #123 from codigoencasa/master
fast
2 parents ad3f6d4 + 4185e01 commit fd983af

File tree

2 files changed

+111
-55
lines changed

2 files changed

+111
-55
lines changed

src/components/mdx.jsx

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ export function Video(props) {
4444
)
4545
}
4646

47+
export function VideoVertical(props) {
48+
return (
49+
<div className='my-6 bg-gray-100 rounded-2xl dark:bg-zinc-800 w-[315px] h-[560px]'>
50+
{props?.label ? <div className="flex py-1 flex-wrap items-start gap-x-4 px-4 dark:border-zinc-800 dark:bg-transparent"><h3 className="mr-auto m-0 text-xs font-thin">{props.label}</h3></div> : <></> }
51+
<iframe width="800" className='rounded-2xl w-full max-sm:w-full max-sm:h-[220px] ' height="530" src={'https://www.youtube.com/embed/'+props.yt} title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen />
52+
</div>
53+
)
54+
}
55+
4756
function InfoIcon(props) {
4857
return (
4958
<svg viewBox="0 0 16 16" aria-hidden="true" {...props}>

src/pages/en/showcases/fast-entires.mdx

+102-55
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,18 @@ import { Guides } from '@/components/Guides'
44

55
export const description = 'Implement message queues for better resource management'
66

7-
# Fast Entires
7+
# Fast Entries
88

9-
## Issue {{not:'true'}}
9+
## Issue
1010
Sometimes it happens that people are impatient and write independent messages in a very short time gap preventing the bot to answer, which makes that each message is answered but not in the desired order.
1111

12-
<Contributors mode users={['robertouski']} />
12+
<Contributors mode users={['robertouski','leifermendez']} />
1313

1414
---
1515

16-
## Possible Solution {{not:'true'}}
16+
## Improved Solution
1717

18-
For this other type of environments you can implement a functionality which you can create to have a margin of 3000ms for the user to write a message, and each time he writes a message in a time less than 3000ms it will accumulate all the messages and then after the margin time the bot will interpret everything as a single conversation.
19-
20-
```mermaid
21-
flowchart LR
22-
n(User) -.m1.-> B((Bot)) -.-> p(Process) --a1--> a(Answers) --> u(User 3 answers)
23-
n(User) -.m2.-> B((Bot)) -.-> p(Process) --a2--> a(Answers) --> u(User 3 answers)
24-
n(User) -.m3.-> B((Bot)) -.-> p(Process) --a3--> a(Answers) --> u(User 3 answers)
25-
```
26-
27-
Applying this implementation, what is achieved is that before passing to the processing stage, all independent messages (3) become one (1) and are processed as an independent message.
18+
For this type of environment, we've implemented an enhanced functionality that introduces a margin of 3000ms for the user to write messages. Each time a user writes a message within this 3000ms window, it accumulates all the messages. After the margin time expires, the bot interprets everything as a single conversation.
2819

2920
```mermaid
3021
flowchart LR
@@ -33,73 +24,109 @@ flowchart LR
3324
n(User) -.m3.-> Q
3425
```
3526

36-
In this example we say __3000ms__ which is equal to 3 seconds but you can modify this to your liking in `MESSAGE_GAP_SECONDS`
27+
This implementation ensures that before passing to the processing stage, all independent messages (e.g., 3) become one (1) and are processed as a single message.
28+
29+
In this example, we use __3000ms__ (equal to 3 seconds) as the default gap, but you can modify this to your liking by adjusting the `gapSeconds` in the `QueueConfig`.
30+
31+
<VideoVertical label="Video Fast Entries" yt="hGTgQDALEmE"/>
3732

3833
<CodeGroup>
3934

4035
```ts {{ title: 'fast-entires.ts' }}
36+
/**
37+
* @file messageQueue.ts
38+
* @description A functional implementation of a message queueing system with debounce functionality.
39+
*/
40+
4141
interface Message {
4242
text: string;
4343
timestamp: number;
4444
}
4545

46-
const messageQueue: Message[] = [];
47-
48-
const MESSAGE_GAP_SECONDS = 3000;
46+
interface QueueConfig {
47+
gapSeconds: number;
48+
}
4949

50-
let messageTimer: NodeJS.Timeout | null = null;
50+
interface QueueState {
51+
queue: Message[];
52+
timer: NodeJS.Timeout | null;
53+
callback: ((body: string) => void) | null;
54+
}
5155

52-
/**
53-
* Adds a message to the queue for later processing.
54-
* @param messageText The text of the message to add to the queue.
55-
* @returns A promise that resolves when the message queue is processed.
56-
*/
57-
async function enqueueMessage(messageText: string): Promise<string> {
58-
messageQueue.push({ text: messageText, timestamp: Date.now() });
59-
60-
return new Promise((resolve) => {
61-
if (messageTimer) {
62-
clearTimeout(messageTimer);
63-
}
64-
65-
messageTimer = setTimeout(() => {
66-
resolve(processMessageQueue());
67-
}, MESSAGE_GAP_SECONDS);
68-
});
56+
function createInitialState(): QueueState {
57+
return {
58+
queue: [],
59+
timer: null,
60+
callback: null
61+
};
6962
}
7063

71-
/**
72-
* Processes the message queue by combining all messages into a single string and clearing the queue.
73-
* @returns The combined string of all messages in the queue.
74-
*/
75-
function processMessageQueue(): string {
76-
if (messageQueue.length === 0) {
77-
return '';
64+
function resetTimer(state: QueueState): QueueState {
65+
if (state.timer) {
66+
clearTimeout(state.timer);
7867
}
68+
return { ...state, timer: null };
69+
}
70+
71+
function processQueue(state: QueueState): [string, QueueState] {
72+
const result = state.queue.map(message => message.text).join(" ");
73+
console.log('Accumulated messages:', result);
7974

80-
const combinedMessage = messageQueue.map(message => message.text).join(" ");
81-
messageQueue.length = 0;
82-
return combinedMessage;
75+
const newState = {
76+
...state,
77+
queue: [],
78+
timer: null
79+
};
80+
81+
return [result, newState];
8382
}
8483

85-
export { enqueueMessage, processMessageQueue };
84+
function createMessageQueue(config: QueueConfig) {
85+
let state = createInitialState();
86+
87+
return function enqueueMessage(messageText: string, callback: (body: string) => void): void {
88+
console.log('Enqueueing:', messageText);
89+
90+
state = resetTimer(state);
91+
state.queue.push({ text: messageText, timestamp: Date.now() });
92+
state.callback = callback;
93+
94+
state.timer = setTimeout(() => {
95+
const [result, newState] = processQueue(state);
96+
state = newState;
97+
if (state.callback) {
98+
state.callback(result);
99+
state.callback = null;
100+
}
101+
}, config.gapSeconds);
102+
};
103+
}
86104

105+
export { createMessageQueue, QueueConfig };
87106
```
107+
88108
```ts {{ title: 'app.ts' }}
89-
import { enqueueMessage } from './utils/fast-entires'
109+
import { createMessageQueue, QueueConfig } from './fast-entires'
90110

91111
import { createBot, createProvider, createFlow, addKeyword, MemoryDB } from '@builderbot/bot'
92112
import { BaileysProvider } from '@builderbot/provider-baileys'
93113

94-
const welcomeFlow = addKeyword<BaileysProvider, MemoryDB>(['hello', 'hi'])
95-
.addAction(async(ctx) => {
96-
const body = await enqueueMessage(ctx.body) // all message merged!
97-
console.log(body)
98-
})
114+
const queueConfig: QueueConfig = { gapSeconds: 3000 };
115+
const enqueueMessage = createMessageQueue(queueConfig);
99116

117+
const welcomeFlow = addKeyword<BaileysProvider, MemoryDB>(['hello', 'hi'])
118+
.addAction(async (ctx, { flowDynamic }) => {
119+
try {
120+
enqueueMessage(ctx.body, async (body) => {
121+
console.log('Processed messages:', body);
122+
await flowDynamic(`Received messages: ${body}`);
123+
});
124+
} catch (error) {
125+
console.error('Error processing message:', error);
126+
}
127+
});
100128

101129
const main = async () => {
102-
103130
const adapterDB = new MemoryDB()
104131
const adapterFlow = createFlow([welcomeFlow])
105132
const adapterProvider = createProvider(BaileysProvider)
@@ -117,7 +144,27 @@ main()
117144
```
118145
</CodeGroup>
119146

120-
Remember that this is an alternative solution, and it is possible that its implementation could be improved.
147+
### Key Improvements in the New Implementation:
148+
149+
1. **Functional Approach**: The new implementation uses a functional programming style, which can lead to more predictable and testable code.
150+
151+
2. **Immutable State**: The state of the queue is managed immutably, which helps prevent unexpected side effects.
152+
153+
3. **Flexible Configuration**: The `QueueConfig` interface allows for easy adjustment of the gap time.
154+
155+
4. **Enhanced Error Handling**: The implementation includes try-catch blocks for better error management.
156+
157+
5. **Callback-based Processing**: Instead of returning a promise, the new implementation uses a callback function, allowing for more flexible message processing.
158+
159+
6. **Detailed Logging**: Console logs have been added at key points to aid in debugging and understanding the message flow.
160+
161+
Remember that while this implementation offers significant improvements, it's always possible to further optimize based on specific use cases and requirements.
162+
163+
----
164+
165+
<Guides />
166+
167+
<Resources />
121168

122169
----
123170

0 commit comments

Comments
 (0)