perf(chatwoot): create cache for the most used/expensive functions in chatwoot

This commit is contained in:
jaison-x 2024-01-03 18:42:54 -03:00
parent 7373eea842
commit f376047632
5 changed files with 102 additions and 2 deletions

View File

@ -548,6 +548,7 @@ export class InstanceController {
switch (state) { switch (state) {
case 'open': case 'open':
this.logger.verbose('logging out instance: ' + instanceName); this.logger.verbose('logging out instance: ' + instanceName);
instance.clearCacheChatwoot();
await instance.reloadConnection(); await instance.reloadConnection();
await delay(2000); await delay(2000);
@ -613,6 +614,7 @@ export class InstanceController {
} }
try { try {
this.waMonitor.waInstances[instanceName]?.removeRabbitmqQueues(); this.waMonitor.waInstances[instanceName]?.removeRabbitmqQueues();
this.waMonitor.waInstances[instanceName]?.clearCacheChatwoot();
if (instance.state === 'connecting') { if (instance.state === 'connecting') {
this.logger.verbose('logging out instance: ' + instanceName); this.logger.verbose('logging out instance: ' + instanceName);

View File

@ -0,0 +1,39 @@
import NodeCache from 'node-cache';
import { Logger } from '../../config/logger.config';
export class CacheService {
private readonly logger = new Logger(CacheService.name);
constructor(private module: string) {}
static localCache = new NodeCache({
stdTTL: 12 * 60 * 60,
});
public get(key: string) {
return CacheService.localCache.get(`${this.module}-${key}`);
}
public set(key: string, value) {
return CacheService.localCache.set(`${this.module}-${key}`, value);
}
public has(key: string) {
return CacheService.localCache.has(`${this.module}-${key}`);
}
public delete(key: string) {
return CacheService.localCache.del(`${this.module}-${key}`);
}
public deleteAll() {
const keys = CacheService.localCache.keys().filter((key) => key.substring(0, this.module.length) === this.module);
return CacheService.localCache.del(keys);
}
public keys() {
return CacheService.localCache.keys();
}
}

View File

@ -1,4 +1,4 @@
import ChatwootClient from '@figuro/chatwoot-sdk'; import ChatwootClient, { conversation, inbox } from '@figuro/chatwoot-sdk';
import axios from 'axios'; import axios from 'axios';
import FormData from 'form-data'; import FormData from 'form-data';
import { createReadStream, unlinkSync, writeFileSync } from 'fs'; import { createReadStream, unlinkSync, writeFileSync } from 'fs';
@ -11,15 +11,17 @@ import { Logger } from '../../config/logger.config';
import { ChatwootDto } from '../dto/chatwoot.dto'; import { ChatwootDto } from '../dto/chatwoot.dto';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '../dto/sendMessage.dto'; import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '../dto/sendMessage.dto';
import { MessageRaw } from '../models'; import { ChatwootRaw, MessageRaw } from '../models';
import { RepositoryBroker } from '../repository/repository.manager'; import { RepositoryBroker } from '../repository/repository.manager';
import { Events } from '../types/wa.types'; import { Events } from '../types/wa.types';
import { CacheService } from './cache.service';
import { WAMonitoringService } from './monitor.service'; import { WAMonitoringService } from './monitor.service';
export class ChatwootService { export class ChatwootService {
private readonly logger = new Logger(ChatwootService.name); private readonly logger = new Logger(ChatwootService.name);
private provider: any; private provider: any;
private cache = new CacheService(ChatwootService.name);
constructor( constructor(
private readonly waMonitor: WAMonitoringService, private readonly waMonitor: WAMonitoringService,
@ -28,6 +30,11 @@ export class ChatwootService {
) {} ) {}
private async getProvider(instance: InstanceDto) { private async getProvider(instance: InstanceDto) {
const cacheKey = `getProvider-${instance.instanceName}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey) as ChatwootRaw;
}
this.logger.verbose('get provider to instance: ' + instance.instanceName); this.logger.verbose('get provider to instance: ' + instance.instanceName);
const provider = await this.waMonitor.waInstances[instance.instanceName]?.findChatwoot(); const provider = await this.waMonitor.waInstances[instance.instanceName]?.findChatwoot();
@ -38,6 +45,8 @@ export class ChatwootService {
this.logger.verbose('provider found'); this.logger.verbose('provider found');
this.cache.set(cacheKey, provider);
return provider; return provider;
// try { // try {
// } catch (error) { // } catch (error) {
@ -60,6 +69,11 @@ export class ChatwootService {
this.provider = provider; this.provider = provider;
const cacheKey = `clientCw-${instance.instanceName}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey) as ChatwootClient;
}
this.logger.verbose('create client to instance: ' + instance.instanceName); this.logger.verbose('create client to instance: ' + instance.instanceName);
const client = new ChatwootClient({ const client = new ChatwootClient({
config: { config: {
@ -72,9 +86,15 @@ export class ChatwootService {
this.logger.verbose('client created'); this.logger.verbose('client created');
this.cache.set(cacheKey, client);
return client; return client;
} }
public getCache() {
return this.cache;
}
public async create(instance: InstanceDto, data: ChatwootDto) { public async create(instance: InstanceDto, data: ChatwootDto) {
this.logger.verbose('create chatwoot: ' + instance.instanceName); this.logger.verbose('create chatwoot: ' + instance.instanceName);
@ -389,6 +409,26 @@ export class ChatwootService {
return null; return null;
} }
const cacheKey = `createConversation-${instance.instanceName}-${body.key.remoteJid}`;
if (this.cache.has(cacheKey)) {
const conversationId = this.cache.get(cacheKey) as number;
let conversationExists: conversation | boolean;
try {
conversationExists = await client.conversations.get({
accountId: this.provider.account_id,
conversationId: conversationId,
});
} catch (error) {
conversationExists = false;
}
if (!conversationExists) {
this.cache.delete(cacheKey);
return await this.createConversation(instance, body);
}
return conversationId;
}
const isGroup = body.key.remoteJid.includes('@g.us'); const isGroup = body.key.remoteJid.includes('@g.us');
this.logger.verbose('is group: ' + isGroup); this.logger.verbose('is group: ' + isGroup);
@ -539,6 +579,7 @@ export class ChatwootService {
if (conversation) { if (conversation) {
this.logger.verbose('conversation found'); this.logger.verbose('conversation found');
this.cache.set(cacheKey, conversation.id);
return conversation.id; return conversation.id;
} }
} }
@ -564,6 +605,7 @@ export class ChatwootService {
} }
this.logger.verbose('conversation created'); this.logger.verbose('conversation created');
this.cache.set(cacheKey, conversation.id);
return conversation.id; return conversation.id;
} catch (error) { } catch (error) {
this.logger.error(error); this.logger.error(error);
@ -573,6 +615,11 @@ export class ChatwootService {
public async getInbox(instance: InstanceDto) { public async getInbox(instance: InstanceDto) {
this.logger.verbose('get inbox to instance: ' + instance.instanceName); this.logger.verbose('get inbox to instance: ' + instance.instanceName);
const cacheKey = `getInbox-${instance.instanceName}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey) as inbox;
}
const client = await this.clientCw(instance); const client = await this.clientCw(instance);
if (!client) { if (!client) {
@ -599,6 +646,7 @@ export class ChatwootService {
} }
this.logger.verbose('return inbox'); this.logger.verbose('return inbox');
this.cache.set(cacheKey, findByName);
return findByName; return findByName;
} }

View File

@ -442,6 +442,7 @@ export class WAMonitoringService {
this.eventEmitter.on('logout.instance', async (instanceName: string) => { this.eventEmitter.on('logout.instance', async (instanceName: string) => {
this.logger.verbose('logout instance: ' + instanceName); this.logger.verbose('logout instance: ' + instanceName);
try { try {
this.waInstances[instanceName]?.clearCacheChatwoot();
this.logger.verbose('request cleaning up instance: ' + instanceName); this.logger.verbose('request cleaning up instance: ' + instanceName);
this.cleaningUp(instanceName); this.cleaningUp(instanceName);
} finally { } finally {

View File

@ -368,6 +368,8 @@ export class WAStartupService {
Object.assign(this.localChatwoot, { ...data, sign_delimiter: data.sign_msg ? data.sign_delimiter : null }); Object.assign(this.localChatwoot, { ...data, sign_delimiter: data.sign_msg ? data.sign_delimiter : null });
this.clearCacheChatwoot();
this.logger.verbose('Chatwoot set'); this.logger.verbose('Chatwoot set');
} }
@ -402,6 +404,14 @@ export class WAStartupService {
}; };
} }
public clearCacheChatwoot() {
this.logger.verbose('Removing cache from chatwoot');
if (this.localChatwoot.enabled) {
this.chatwootService.getCache().deleteAll();
}
}
private async loadSettings() { private async loadSettings() {
this.logger.verbose('Loading settings'); this.logger.verbose('Loading settings');
const data = await this.repository.settings.find(this.instanceName); const data = await this.repository.settings.find(this.instanceName);