feat: implement Redis caching with locking and optimized product search in SalesService and update compression dependency
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 2m52s
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 2m52s
This commit is contained in:
45
package-lock.json
generated
45
package-lock.json
generated
@@ -20,7 +20,7 @@
|
||||
"@types/cache-manager": "^3.4.3",
|
||||
"cache-manager": "^3.6.3",
|
||||
"cache-manager-redis-store": "^3.0.1",
|
||||
"compression": "^1.7.4",
|
||||
"compression": "^1.8.1",
|
||||
"crc": "^4.3.2",
|
||||
"fs": "0.0.1-security",
|
||||
"guid-typescript": "^1.0.9",
|
||||
@@ -4181,16 +4181,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/compression": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
|
||||
"integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
|
||||
"integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.5",
|
||||
"bytes": "3.0.0",
|
||||
"compressible": "~2.0.16",
|
||||
"bytes": "3.1.2",
|
||||
"compressible": "~2.0.18",
|
||||
"debug": "2.6.9",
|
||||
"on-headers": "~1.0.2",
|
||||
"safe-buffer": "5.1.2",
|
||||
"negotiator": "~0.6.4",
|
||||
"on-headers": "~1.1.0",
|
||||
"safe-buffer": "5.2.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -4198,17 +4199,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/compression/node_modules/bytes": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/compression/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
"node_modules/compression/node_modules/negotiator": {
|
||||
"version": "0.6.4",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
|
||||
"integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
@@ -9810,9 +9816,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/on-headers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/cache-manager": "^3.4.3",
|
||||
"cache-manager": "^3.6.3",
|
||||
"cache-manager-redis-store": "^3.0.1",
|
||||
"compression": "^1.7.4",
|
||||
"compression": "^1.8.1",
|
||||
"crc": "^4.3.2",
|
||||
"fs": "0.0.1-security",
|
||||
"guid-typescript": "^1.0.9",
|
||||
|
||||
@@ -27,8 +27,39 @@ export class SalesService {
|
||||
|
||||
|
||||
async GetProducts2(store: string, pageSize: number, pageNumber: number, filter: FilterProduct = null,) {
|
||||
const connectionDb = new Connection(connectionOptions);
|
||||
await connectionDb.connect();
|
||||
const cacheKey = `GetProducts2:${store}:${pageSize}:${pageNumber}:${JSON.stringify(filter)}`;
|
||||
const lockKey = `lock:${cacheKey}`;
|
||||
const lockTimeout = 30;
|
||||
|
||||
// Fase 1: Verificar cache Redis
|
||||
try {
|
||||
const cachedResult = await this.redisClient.get(cacheKey);
|
||||
if (cachedResult) {
|
||||
console.log('GetProducts2 - Retornando resultado do cache');
|
||||
return JSON.parse(cachedResult);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erro ao acessar o Redis no GetProducts2:', err?.message || err);
|
||||
}
|
||||
|
||||
// Lock para evitar thundering herd
|
||||
const lockValue = Date.now() + lockTimeout * 1000 + 1;
|
||||
let acquiredLock: string | null = null;
|
||||
try {
|
||||
acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout);
|
||||
} catch (err) {
|
||||
console.error('Erro ao adquirir lock no Redis (GetProducts2):', err?.message || err);
|
||||
acquiredLock = 'OK'; // Em caso de erro no Redis, prosseguir sem lock
|
||||
}
|
||||
|
||||
if (acquiredLock !== 'OK') {
|
||||
console.log('Lock não adquirido (GetProducts2), aguardando...');
|
||||
await this.sleep(1000);
|
||||
return this.GetProducts2(store, pageSize, pageNumber, filter);
|
||||
}
|
||||
|
||||
// Fase 2: Reutilizar conexão via pool
|
||||
const connectionDb = getConnection();
|
||||
const queryRunner = connectionDb.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
try {
|
||||
@@ -38,55 +69,11 @@ export class SalesService {
|
||||
pageNumber = 1;
|
||||
const offSet = (pageNumber - 1) * pageSize;
|
||||
|
||||
const sqlProduto = `SELECT
|
||||
esvlistaprodutos.CODPROD as "idProduct",
|
||||
esvlistaprodutos.SEQ as "seq",
|
||||
esvlistaprodutos.DESCRICAO as "smallDescription",
|
||||
esvlistaprodutos.NOMEECOMMERCE as "title",
|
||||
esvlistaprodutos.CODFAB as "idProvider",
|
||||
esvlistaprodutos.CODAUXILIAR as "ean",
|
||||
esvlistaprodutos.TIPOPRODUTO as "productType",
|
||||
esvlistaprodutos.DADOSTECNICOS as "technicalData",
|
||||
esvlistaprodutos.INFORMACOESTECNICAS as "description",
|
||||
esvlistaprodutos.URLIMAGEM as "urlImage",
|
||||
esvlistaprodutos.NOMEMARCA as "brand",
|
||||
esvlistaprodutos.NOMEDEPARTAMENTO as "department",
|
||||
esvlistaprodutos.NOMESECAO as "section",
|
||||
esvlistaprodutos.NOMECATEGORIA as "category",
|
||||
esvlistaprodutos.NOMEFORNECEDOR as "supplier",
|
||||
esvlistaprodutos.CODIGOFILIAL as "store",
|
||||
esvlistaprodutos.CLASSEVENDA as "saleAbc",
|
||||
esvlistaprodutos.CLASSEESTOQUE as "stockAbc",
|
||||
esvlistaprodutos.FORALINHA as "outLine",
|
||||
esvlistaprodutos.PRECOVENDA as "listPrice",
|
||||
esvlistaprodutos.PRECOPROMOCIONAL as "salePrice",
|
||||
esvlistaprodutos.PRECOPROMOCIONAL as "salePromotion",
|
||||
esvlistaprodutos.PRECOPROMOCIONAL_AVISTA as "salePromotion_cash",
|
||||
esvlistaprodutos.PERCENTUALDESCONTO as "offPercent",
|
||||
esvlistaprodutos.QTESTOQUE_DISPONIVEL as "stock",
|
||||
esvlistaprodutos.QTCAIXAS as "boxStock",
|
||||
esvlistaprodutos.ESTOQUE_DISP_LOJA as "store_stock",
|
||||
esvlistaprodutos.ESTOQUE_DISP_CAIXA_LOJA as "store_boxStock",
|
||||
esvlistaprodutos.MULTIPLO as "mutiple",
|
||||
esvlistaprodutos.UNIDADE as "unity",
|
||||
esvlistaprodutos.URLDEPARTAMENTO as "urlDepartment",
|
||||
esvlistaprodutos.URLSECAO as "urlSection",
|
||||
esvlistaprodutos.PRODUTO_COM_REDUCAO_PRECO as "downPrice",
|
||||
esvlistaprodutos.PRODUTO_EM_CAMPANHA as "compaing",
|
||||
esvlistaprodutos.BASETINTOMETRICO as "base",
|
||||
esvlistaprodutos.LETRABASETINTOMETRICO as "letter",
|
||||
esvlistaprodutos.LINHATINTOMETRICO as "line",
|
||||
esvlistaprodutos.LITRAGEM as "can",
|
||||
esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock",
|
||||
esvlistaprodutos.TEM_PRODUTO_SIMILAR as "similar",
|
||||
NVL(esvlistaprodutos.TIPO, 'SEM') as "type_campaing"
|
||||
FROM ESVLISTAPRODUTOS
|
||||
WHERE 1 = 1 `;
|
||||
|
||||
if (filter && filter.text.length > 0) {
|
||||
const description = filter.text.toUpperCase();
|
||||
console.log('consultando por codigo de fabrica');
|
||||
console.log('consultando por texto: ' + description);
|
||||
|
||||
// Fase 3: Query unificada - busca por CODFAB OU DESCRICAO em uma única query
|
||||
let products = await queryRunner.manager
|
||||
.getRepository(SalesProduct)
|
||||
.createQueryBuilder('esvlistaprodutos')
|
||||
@@ -97,8 +84,6 @@ export class SalesService {
|
||||
.addSelect("\"esvlistaprodutos\".CODFAB", "idProvider")
|
||||
.addSelect("\"esvlistaprodutos\".CODAUXILIAR", "ean")
|
||||
.addSelect("\"esvlistaprodutos\".TIPOPRODUTO", "productType")
|
||||
.addSelect("\"esvlistaprodutos\".DADOSTECNICOS", "technicalData")
|
||||
.addSelect("\"esvlistaprodutos\".INFORMACOESTECNICAS", "description")
|
||||
.addSelect("\"esvlistaprodutos\".URLIMAGEM", "urlImage")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEMARCA", "brand")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEDEPARTAMENTO", "department")
|
||||
@@ -131,66 +116,7 @@ export class SalesService {
|
||||
.addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock")
|
||||
.addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar")
|
||||
.addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing")
|
||||
.where("UPPER(\"esvlistaprodutos\".CODFAB) LIKE '%'||REPLACE(:description, '@', '%')||'%'", { description })
|
||||
.andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store })
|
||||
.andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')",
|
||||
{ produtoComReducaoPreco: (filter.markdown) ? 'S' : 'N' })
|
||||
.andWhere("(\"esvlistaprodutos\".produto_em_campanha = :campaign OR :campaign = 'N')",
|
||||
{ campaign: (filter.campaign) ? 'I' : 'N' })
|
||||
.andWhere("(\"esvlistaprodutos\".produto_em_campanha = :oportunity OR :oportunity = 'N')",
|
||||
{ oportunity: (filter.oportunity) ? 'O' : 'N' })
|
||||
.andWhere("(\"esvlistaprodutos\".produto_em_promocao = :produtoEmPromocao OR :produtoEmPromocao = 'N')",
|
||||
{ produtoEmPromocao: (filter.promotion) ? 'S' : 'N' })
|
||||
.limit(pageSize)
|
||||
.offset(offSet)
|
||||
.orderBy("\"esvlistaprodutos\".DESCRICAO", "ASC")
|
||||
.getRawMany();
|
||||
if (products.length == 0) {
|
||||
products = await queryRunner.manager
|
||||
.getRepository(SalesProduct)
|
||||
.createQueryBuilder('esvlistaprodutos')
|
||||
.select("\"esvlistaprodutos\".CODPROD", "idProduct")
|
||||
.addSelect("\"esvlistaprodutos\".SEQ", "seq")
|
||||
.addSelect("\"esvlistaprodutos\".DESCRICAO", "smallDescription")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEECOMMERCE", "title")
|
||||
.addSelect("\"esvlistaprodutos\".CODFAB", "idProvider")
|
||||
.addSelect("\"esvlistaprodutos\".CODAUXILIAR", "ean")
|
||||
.addSelect("\"esvlistaprodutos\".TIPOPRODUTO", "productType")
|
||||
.addSelect("\"esvlistaprodutos\".DADOSTECNICOS", "technicalData")
|
||||
.addSelect("\"esvlistaprodutos\".INFORMACOESTECNICAS", "description")
|
||||
.addSelect("\"esvlistaprodutos\".URLIMAGEM", "urlImage")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEMARCA", "brand")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEDEPARTAMENTO", "department")
|
||||
.addSelect("\"esvlistaprodutos\".NOMESECAO", "section")
|
||||
.addSelect("\"esvlistaprodutos\".NOMECATEGORIA", "category")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEFORNECEDOR", "supplier")
|
||||
.addSelect("\"esvlistaprodutos\".CODIGOFILIAL", "store")
|
||||
.addSelect("\"esvlistaprodutos\".CLASSEVENDA", "saleAbc")
|
||||
.addSelect("\"esvlistaprodutos\".CLASSEESTOQUE", "stockAbc")
|
||||
.addSelect("\"esvlistaprodutos\".FORALINHA", "outLine")
|
||||
.addSelect("\"esvlistaprodutos\".PRECOVENDA", "listPrice")
|
||||
.addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePrice")
|
||||
.addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL", "salePromotion")
|
||||
.addSelect("\"esvlistaprodutos\".PRECOPROMOCIONAL_AVISTA", "salePromotion_cash")
|
||||
.addSelect("\"esvlistaprodutos\".PERCENTUALDESCONTO", "offPercent")
|
||||
.addSelect("\"esvlistaprodutos\".QTESTOQUE_DISPONIVEL", "stock")
|
||||
.addSelect("\"esvlistaprodutos\".QTCAIXAS", "boxStock")
|
||||
.addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_LOJA", "store_stock")
|
||||
.addSelect("\"esvlistaprodutos\".ESTOQUE_DISP_CAIXA_LOJA", "store_boxStock")
|
||||
.addSelect("\"esvlistaprodutos\".MULTIPLO", "mutiple")
|
||||
.addSelect("\"esvlistaprodutos\".UNIDADE", "unity")
|
||||
.addSelect("\"esvlistaprodutos\".URLDEPARTAMENTO", "urlDepartment")
|
||||
.addSelect("\"esvlistaprodutos\".URLSECAO", "urlSection")
|
||||
.addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice")
|
||||
.addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing")
|
||||
.addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base")
|
||||
.addSelect("\"esvlistaprodutos\".LETRABASETINTOMETRICO", "letter")
|
||||
.addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line")
|
||||
.addSelect("\"esvlistaprodutos\".LITRAGEM", "can")
|
||||
.addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock")
|
||||
.addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar")
|
||||
.addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing")
|
||||
.where("UPPER(\"esvlistaprodutos\".descricao) LIKE '%'||REPLACE(:description, '@', '%')||'%'", { description })
|
||||
.where("(UPPER(\"esvlistaprodutos\".CODFAB) LIKE '%'||REPLACE(:description, '@', '%')||'%' OR UPPER(\"esvlistaprodutos\".descricao) LIKE '%'||REPLACE(:description, '@', '%')||'%')", { description })
|
||||
.andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store })
|
||||
.andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')",
|
||||
{ produtoComReducaoPreco: (filter.markdown) ? 'S' : 'N' })
|
||||
@@ -200,14 +126,13 @@ export class SalesService {
|
||||
{ oportunity: (filter.oportunity) ? 'O' : 'N' })
|
||||
.andWhere("(\"esvlistaprodutos\".produto_em_promocao = :produtoEmPromocao OR :produtoEmPromocao = 'N')",
|
||||
{ produtoEmPromocao: (filter.promotion) ? 'S' : 'N' })
|
||||
.orderBy("\"esvlistaprodutos\".CLASSEVENDA")
|
||||
.limit(pageSize)
|
||||
.offset(offSet)
|
||||
.orderBy("\"esvlistaprodutos\".DESCRICAO", "ASC")
|
||||
.getRawMany();
|
||||
}
|
||||
products = this.createListImages(products);
|
||||
console.log(products.length + ' produtos');
|
||||
try { await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 900); } catch (cacheErr) { console.error('Erro ao salvar cache GetProducts2:', cacheErr?.message || cacheErr); }
|
||||
return products;
|
||||
}
|
||||
|
||||
@@ -234,8 +159,6 @@ export class SalesService {
|
||||
.addSelect("\"esvlistaprodutos\".CODFAB", "idProvider")
|
||||
.addSelect("\"esvlistaprodutos\".CODAUXILIAR", "ean")
|
||||
.addSelect("\"esvlistaprodutos\".TIPOPRODUTO", "productType")
|
||||
.addSelect("\"esvlistaprodutos\".DADOSTECNICOS", "technicalData")
|
||||
.addSelect("\"esvlistaprodutos\".INFORMACOESTECNICAS", "description")
|
||||
.addSelect("\"esvlistaprodutos\".URLIMAGEM", "urlImage")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEMARCA", "brand")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEDEPARTAMENTO", "department")
|
||||
@@ -285,6 +208,7 @@ export class SalesService {
|
||||
.getRawMany();
|
||||
products = this.createListImages(products);
|
||||
console.log(products.length + ' produtos');
|
||||
try { await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 900); } catch (cacheErr) { console.error('Erro ao salvar cache GetProducts2:', cacheErr?.message || cacheErr); }
|
||||
return products;
|
||||
|
||||
} else {
|
||||
@@ -300,8 +224,6 @@ export class SalesService {
|
||||
.addSelect("\"esvlistaprodutos\".CODFAB", "idProvider")
|
||||
.addSelect("\"esvlistaprodutos\".CODAUXILIAR", "ean")
|
||||
.addSelect("\"esvlistaprodutos\".TIPOPRODUTO", "productType")
|
||||
.addSelect("\"esvlistaprodutos\".DADOSTECNICOS", "technicalData")
|
||||
.addSelect("\"esvlistaprodutos\".INFORMACOESTECNICAS", "description")
|
||||
.addSelect("\"esvlistaprodutos\".URLIMAGEM", "urlImage")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEMARCA", "brand")
|
||||
.addSelect("\"esvlistaprodutos\".NOMEDEPARTAMENTO", "department")
|
||||
@@ -349,6 +271,7 @@ export class SalesService {
|
||||
.getRawMany();
|
||||
products = this.createListImages(products);
|
||||
console.log(products.length + ' produtos');
|
||||
try { await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 900); } catch (cacheErr) { console.error('Erro ao salvar cache GetProducts2:', cacheErr?.message || cacheErr); }
|
||||
return products;
|
||||
|
||||
}
|
||||
@@ -357,7 +280,15 @@ export class SalesService {
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
await connectionDb.close();
|
||||
// Não fecha a conexão - reutilizada pelo pool
|
||||
try {
|
||||
const currentLockValue = await this.redisClient.get(lockKey);
|
||||
if (currentLockValue === lockValue.toString()) {
|
||||
await this.redisClient.del(lockKey);
|
||||
}
|
||||
} catch (lockErr) {
|
||||
console.error('Erro ao liberar lock Redis (GetProducts2):', lockErr?.message || lockErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1114,17 +1045,18 @@ export class SalesService {
|
||||
}
|
||||
|
||||
createListImages(products: SalesProduct[]): SalesProduct[] {
|
||||
products.forEach(product => {
|
||||
for (let i = 0; i < products.length; i++) {
|
||||
const product = products[i];
|
||||
product.images = [];
|
||||
if (product.urlImage != null) {
|
||||
let urlImage = product.urlImage;
|
||||
if (urlImage.indexOf(";") == -1) {
|
||||
urlImage += ";";
|
||||
if (product.urlImage != null && product.urlImage.length > 0) {
|
||||
product.images = product.urlImage
|
||||
.split(';')
|
||||
.map(img => img.trim())
|
||||
.filter(img => img.length > 0);
|
||||
}
|
||||
const images = product.urlImage.split(";");
|
||||
product.images = images.map(i => i.trim());
|
||||
// Adiciona thumbnail para acesso rápido no frontend
|
||||
(product as any).thumbnail = product.images.length > 0 ? product.images[0] : null;
|
||||
}
|
||||
});
|
||||
return products;
|
||||
}
|
||||
|
||||
@@ -1415,8 +1347,7 @@ export class SalesService {
|
||||
const skipReg = ((pageNumber - 1) * pageSize);
|
||||
const pagination = ` OFFSET ${skipReg} ROWS FETCH NEXT ${pageSize} ROWS ONLY`;
|
||||
|
||||
const connectionDb = new Connection(connectionOptions);
|
||||
await connectionDb.connect();
|
||||
const connectionDb = getConnection();
|
||||
const queryRunner = connectionDb.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
|
||||
@@ -1425,7 +1356,7 @@ export class SalesService {
|
||||
products = this.createListImages(products);
|
||||
console.log("Total de produtos: " + products.length);
|
||||
|
||||
await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 3600);
|
||||
await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 900);
|
||||
|
||||
return products;
|
||||
} catch (err) {
|
||||
@@ -1433,7 +1364,7 @@ export class SalesService {
|
||||
throw err;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
await connectionDb.close();
|
||||
// Não fecha a conexão - reutilizada pelo pool
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user