Skip to content

Commit 0935155

Browse files
committed
refactor(chatbot): refatorar conexão com PostgreSQL e melhorar tratamento de mensagens
- Alterado método de obtenção da conexão PostgreSQL para ser assíncrono, melhorando a gestão de conexões. - Implementada lógica de retry para criação de mensagens e conversas, garantindo maior robustez em caso de falhas. - Ajustadas chamadas de consulta ao banco de dados para utilizar a nova abordagem de conexão. - Adicionada nova propriedade `messageBodyForRetry` para facilitar o reenvio de mensagens em caso de erro.
1 parent d8268b0 commit 0935155

1 file changed

Lines changed: 139 additions & 61 deletions

File tree

src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts

Lines changed: 139 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ export class ChatwootService {
5353
private readonly cache: CacheService,
5454
) {}
5555

56-
private pgClient = postgresClient.getChatwootConnection();
56+
private async getPgClient() {
57+
return postgresClient.getChatwootConnection();
58+
}
5759

5860
private async getProvider(instance: InstanceDto): Promise<ChatwootModel | null> {
5961
const cacheKey = `${instance.instanceName}:getProvider`;
@@ -382,7 +384,8 @@ export class ChatwootService {
382384
if (!uri) return false;
383385

384386
const sqlTags = `SELECT id, taggings_count FROM tags WHERE name = $1 LIMIT 1`;
385-
const tagData = (await this.pgClient.query(sqlTags, [nameInbox]))?.rows[0];
387+
const pgClient = await this.getPgClient();
388+
const tagData = (await pgClient.query(sqlTags, [nameInbox]))?.rows[0];
386389
let tagId = tagData?.id;
387390
const taggingsCount = tagData?.taggings_count || 0;
388391

@@ -392,18 +395,18 @@ export class ChatwootService {
392395
DO UPDATE SET taggings_count = tags.taggings_count + 1
393396
RETURNING id`;
394397

395-
tagId = (await this.pgClient.query(sqlTag, [nameInbox, taggingsCount + 1]))?.rows[0]?.id;
398+
tagId = (await pgClient.query(sqlTag, [nameInbox, taggingsCount + 1]))?.rows[0]?.id;
396399

397400
const sqlCheckTagging = `SELECT 1 FROM taggings
398401
WHERE tag_id = $1 AND taggable_type = 'Contact' AND taggable_id = $2 AND context = 'labels' LIMIT 1`;
399402

400-
const taggingExists = (await this.pgClient.query(sqlCheckTagging, [tagId, contactId]))?.rowCount > 0;
403+
const taggingExists = (await pgClient.query(sqlCheckTagging, [tagId, contactId]))?.rowCount > 0;
401404

402405
if (!taggingExists) {
403406
const sqlInsertLabel = `INSERT INTO taggings (tag_id, taggable_type, taggable_id, context, created_at)
404407
VALUES ($1, 'Contact', $2, 'labels', NOW())`;
405408

406-
await this.pgClient.query(sqlInsertLabel, [tagId, contactId]);
409+
await pgClient.query(sqlInsertLabel, [tagId, contactId]);
407410
}
408411

409412
return true;
@@ -861,6 +864,7 @@ export class ChatwootService {
861864
messageBody?: any,
862865
sourceId?: string,
863866
quotedMsg?: MessageModel,
867+
messageBodyForRetry?: any,
864868
) {
865869
const client = await this.clientCw(instance);
866870

@@ -869,32 +873,66 @@ export class ChatwootService {
869873
return null;
870874
}
871875

872-
const replyToIds = await this.getReplyToIds(messageBody, instance);
876+
const doCreateMessage = async (convId: number) => {
877+
const replyToIds = await this.getReplyToIds(messageBody, instance);
873878

874-
const sourceReplyId = quotedMsg?.chatwootMessageId || null;
879+
const sourceReplyId = quotedMsg?.chatwootMessageId || null;
875880

876-
const message = await client.messages.create({
877-
accountId: this.provider.accountId,
878-
conversationId: conversationId,
879-
data: {
880-
content: content,
881-
message_type: messageType,
882-
attachments: attachments,
883-
private: privateMessage || false,
884-
source_id: sourceId,
885-
content_attributes: {
886-
...replyToIds,
881+
const message = await client.messages.create({
882+
accountId: this.provider.accountId,
883+
conversationId: convId,
884+
data: {
885+
content: content,
886+
message_type: messageType,
887+
attachments: attachments,
888+
private: privateMessage || false,
889+
source_id: sourceId,
890+
content_attributes: {
891+
...replyToIds,
892+
},
893+
source_reply_id: sourceReplyId ? sourceReplyId.toString() : null,
887894
},
888-
source_reply_id: sourceReplyId ? sourceReplyId.toString() : null,
889-
},
890-
});
895+
});
891896

892-
if (!message) {
893-
this.logger.warn('message not found');
894-
return null;
895-
}
897+
if (!message) {
898+
this.logger.warn('message not found');
899+
return null;
900+
}
896901

897-
return message;
902+
return message;
903+
};
904+
905+
try {
906+
return await doCreateMessage(conversationId);
907+
} catch (error) {
908+
const errorMessage = error.toString().toLowerCase();
909+
const status = error.response?.status;
910+
if (errorMessage.includes('not found') || status === 404) {
911+
this.logger.warn(`Conversation ${conversationId} not found. Retrying...`);
912+
const bodyForRetry = messageBodyForRetry || messageBody;
913+
914+
if (!bodyForRetry) {
915+
this.logger.error('Cannot retry createMessage without a message body for context.');
916+
return null;
917+
}
918+
919+
const remoteJid = bodyForRetry.key.remoteJid;
920+
const cacheKey = `${instance.instanceName}:createConversation-${remoteJid}`;
921+
await this.cache.delete(cacheKey);
922+
923+
const newConversationId = await this.createConversation(instance, bodyForRetry);
924+
if (!newConversationId) {
925+
this.logger.error(`Failed to create new conversation for ${remoteJid}`);
926+
return null;
927+
}
928+
929+
this.logger.log(`Retrying message creation for ${remoteJid} with new conversation ${newConversationId}`);
930+
return await doCreateMessage(newConversationId);
931+
} else {
932+
this.logger.error(`Error creating message: ${error}`);
933+
throw error;
934+
}
935+
}
898936
}
899937

900938
public async getOpenConversationByContact(
@@ -987,6 +1025,7 @@ export class ChatwootService {
9871025
messageBody?: any,
9881026
sourceId?: string,
9891027
quotedMsg?: MessageModel,
1028+
messageBodyForRetry?: any,
9901029
) {
9911030
if (sourceId && this.isImportHistoryAvailable()) {
9921031
const messageAlreadySaved = await chatwootImport.getExistingSourceIds([sourceId], conversationId);
@@ -997,54 +1036,84 @@ export class ChatwootService {
9971036
}
9981037
}
9991038
}
1000-
const data = new FormData();
1039+
const doSendData = async (convId: number) => {
1040+
const data = new FormData();
10011041

1002-
if (content) {
1003-
data.append('content', content);
1004-
}
1042+
if (content) {
1043+
data.append('content', content);
1044+
}
10051045

1006-
data.append('message_type', messageType);
1046+
data.append('message_type', messageType);
10071047

1008-
data.append('attachments[]', fileStream, { filename: fileName });
1048+
data.append('attachments[]', fileStream, { filename: fileName });
10091049

1010-
const sourceReplyId = quotedMsg?.chatwootMessageId || null;
1050+
const sourceReplyId = quotedMsg?.chatwootMessageId || null;
10111051

1012-
if (messageBody && instance) {
1013-
const replyToIds = await this.getReplyToIds(messageBody, instance);
1052+
if (messageBody && instance) {
1053+
const replyToIds = await this.getReplyToIds(messageBody, instance);
10141054

1015-
if (replyToIds.in_reply_to || replyToIds.in_reply_to_external_id) {
1016-
const content = JSON.stringify({
1017-
...replyToIds,
1018-
});
1019-
data.append('content_attributes', content);
1055+
if (replyToIds.in_reply_to || replyToIds.in_reply_to_external_id) {
1056+
const content = JSON.stringify({
1057+
...replyToIds,
1058+
});
1059+
data.append('content_attributes', content);
1060+
}
10201061
}
1021-
}
10221062

1023-
if (sourceReplyId) {
1024-
data.append('source_reply_id', sourceReplyId.toString());
1025-
}
1063+
if (sourceReplyId) {
1064+
data.append('source_reply_id', sourceReplyId.toString());
1065+
}
10261066

1027-
if (sourceId) {
1028-
data.append('source_id', sourceId);
1029-
}
1067+
if (sourceId) {
1068+
data.append('source_id', sourceId);
1069+
}
10301070

1031-
const config = {
1032-
method: 'post',
1033-
maxBodyLength: Infinity,
1034-
url: `${this.provider.url}/api/v1/accounts/${this.provider.accountId}/conversations/${conversationId}/messages`,
1035-
headers: {
1036-
api_access_token: this.provider.token,
1037-
...data.getHeaders(),
1038-
},
1039-
data: data,
1071+
const config = {
1072+
method: 'post',
1073+
maxBodyLength: Infinity,
1074+
url: `${this.provider.url}/api/v1/accounts/${this.provider.accountId}/conversations/${convId}/messages`,
1075+
headers: {
1076+
api_access_token: this.provider.token,
1077+
...data.getHeaders(),
1078+
},
1079+
data: data,
1080+
};
1081+
1082+
const { data: responseData } = await axios.request(config);
1083+
return responseData;
10401084
};
10411085

10421086
try {
1043-
const { data } = await axios.request(config);
1044-
1045-
return data;
1087+
return await doSendData(conversationId);
10461088
} catch (error) {
1047-
this.logger.error(error);
1089+
const errorMessage = error.toString().toLowerCase();
1090+
const status = error.response?.status;
1091+
1092+
if (errorMessage.includes('not found') || status === 404) {
1093+
this.logger.warn(`Conversation ${conversationId} not found. Retrying...`);
1094+
const bodyForRetry = messageBodyForRetry || messageBody;
1095+
1096+
if (!bodyForRetry) {
1097+
this.logger.error('Cannot retry sendData without a message body for context.');
1098+
return null;
1099+
}
1100+
1101+
const remoteJid = bodyForRetry.key.remoteJid;
1102+
const cacheKey = `${instance.instanceName}:createConversation-${remoteJid}`;
1103+
await this.cache.delete(cacheKey);
1104+
1105+
const newConversationId = await this.createConversation(instance, bodyForRetry);
1106+
if (!newConversationId) {
1107+
this.logger.error(`Failed to create new conversation for ${remoteJid}`);
1108+
return null;
1109+
}
1110+
1111+
this.logger.log(`Retrying sendData for ${remoteJid} with new conversation ${newConversationId}`);
1112+
return await doSendData(newConversationId);
1113+
} else {
1114+
this.logger.error(error);
1115+
return null;
1116+
}
10481117
}
10491118
}
10501119

@@ -2032,6 +2101,7 @@ export class ChatwootService {
20322101
body,
20332102
'WAID:' + body.key.id,
20342103
quotedMsg,
2104+
null,
20352105
);
20362106

20372107
if (!send) {
@@ -2051,6 +2121,7 @@ export class ChatwootService {
20512121
body,
20522122
'WAID:' + body.key.id,
20532123
quotedMsg,
2124+
null,
20542125
);
20552126

20562127
if (!send) {
@@ -2076,6 +2147,7 @@ export class ChatwootService {
20762147
},
20772148
'WAID:' + body.key.id,
20782149
quotedMsg,
2150+
body,
20792151
);
20802152
if (!send) {
20812153
this.logger.warn('message not sent');
@@ -2132,6 +2204,8 @@ export class ChatwootService {
21322204
instance,
21332205
body,
21342206
'WAID:' + body.key.id,
2207+
quotedMsg,
2208+
null,
21352209
);
21362210

21372211
if (!send) {
@@ -2173,6 +2247,7 @@ export class ChatwootService {
21732247
body,
21742248
'WAID:' + body.key.id,
21752249
quotedMsg,
2250+
null,
21762251
);
21772252

21782253
if (!send) {
@@ -2192,6 +2267,7 @@ export class ChatwootService {
21922267
body,
21932268
'WAID:' + body.key.id,
21942269
quotedMsg,
2270+
null,
21952271
);
21962272

21972273
if (!send) {
@@ -2262,6 +2338,7 @@ export class ChatwootService {
22622338
},
22632339
'WAID:' + body.key.id,
22642340
null,
2341+
body,
22652342
);
22662343
if (!send) {
22672344
this.logger.warn('edited message not sent');
@@ -2515,7 +2592,8 @@ export class ChatwootService {
25152592
and created_at >= now() - interval '6h'
25162593
order by created_at desc`;
25172594

2518-
const messagesData = (await this.pgClient.query(sqlMessages))?.rows;
2595+
const pgClient = await this.getPgClient();
2596+
const messagesData = (await pgClient.query(sqlMessages))?.rows;
25192597
const ids: string[] = messagesData
25202598
.filter((message) => !!message.source_id)
25212599
.map((message) => message.source_id.replace('WAID:', ''));

0 commit comments

Comments
 (0)