From 5227a96319416585de3a04f873487c02e8434686 Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Fri, 30 Aug 2024 10:00:28 +0000 Subject: [PATCH 1/2] fix: await transaction commit and rollback and avoid unhandledPromise error --- package-lock.json | 48 +++++++++++++++++++++---------------------- package.json | 8 ++++---- src/model/fxQuotes.js | 8 ++++---- src/model/quotes.js | 11 +++++----- 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index 380a71ea..f95b9da8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,17 +15,17 @@ "@hapi/vision": "7.0.3", "@mojaloop/central-services-error-handling": "13.0.1", "@mojaloop/central-services-health": "15.0.0", - "@mojaloop/central-services-logger": "11.5.0", + "@mojaloop/central-services-logger": "11.5.1", "@mojaloop/central-services-metrics": "12.0.8", "@mojaloop/central-services-shared": "18.5.0-snapshot.2", "@mojaloop/central-services-stream": "11.3.1", "@mojaloop/event-sdk": "14.1.1", - "@mojaloop/inter-scheme-proxy-cache-lib": "2.2.0", + "@mojaloop/inter-scheme-proxy-cache-lib": "2.3.0", "@mojaloop/ml-number": "11.2.4", "@mojaloop/sdk-standard-components": "18.1.0", "ajv": "8.17.1", "ajv-keywords": "5.1.0", - "axios": "1.7.4", + "axios": "1.7.5", "blipp": "4.0.2", "commander": "12.1.0", "event-stream": "4.0.1", @@ -46,7 +46,7 @@ "audit-ci": "^7.1.0", "eslint": "8.16.0", "eslint-config-standard": "17.1.0", - "eslint-plugin-jest": "28.8.0", + "eslint-plugin-jest": "28.8.1", "jest": "29.7.0", "jest-junit": "16.0.0", "npm-check-updates": "17.1.0", @@ -1819,14 +1819,14 @@ } }, "node_modules/@mojaloop/central-services-logger": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-logger/-/central-services-logger-11.5.0.tgz", - "integrity": "sha512-pH73RiJ5fKTBTSdLocp1vPBad1D+Kh0HufdcfjLaBQj3dIBq72si0k+Z3L1MeOmMqMzpj+8M/he/izlgqJjVJA==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-logger/-/central-services-logger-11.5.1.tgz", + "integrity": "sha512-l+6+w35NqFJn1Xl82l55x71vCARWTkO6hYAgwbFuqVRqX0jqaRi4oiXG2WwPRVMLqVv8idAboCMX/I6vg/d4Kw==", "dependencies": { "parse-strings-in-object": "2.0.0", "rc": "1.2.8", "safe-stable-stringify": "^2.4.3", - "winston": "3.13.1" + "winston": "3.14.2" } }, "node_modules/@mojaloop/central-services-metrics": { @@ -2012,11 +2012,11 @@ } }, "node_modules/@mojaloop/inter-scheme-proxy-cache-lib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@mojaloop/inter-scheme-proxy-cache-lib/-/inter-scheme-proxy-cache-lib-2.2.0.tgz", - "integrity": "sha512-QrbJlhy7f7Tf1DTjspxqtw0oN3eUAm5zKfCm7moQIYFEV3MYF3rsbODLpgxyzmAO8FFi2Dky/ff7QMVnlA/P9A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@mojaloop/inter-scheme-proxy-cache-lib/-/inter-scheme-proxy-cache-lib-2.3.0.tgz", + "integrity": "sha512-k24azZiBhj8rbszwpsaEfjcMvWFpeT0MfRkU3haiPTPqiV6dFplIBV+Poi4F9a9Ei+X3qcUfZdvU0TWVMR4pbA==", "dependencies": { - "@mojaloop/central-services-logger": "11.5.0", + "@mojaloop/central-services-logger": "11.5.1", "ajv": "^8.17.1", "convict": "^6.2.4", "fast-safe-stringify": "^2.1.1", @@ -2877,9 +2877,9 @@ } }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -5277,9 +5277,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "28.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.0.tgz", - "integrity": "sha512-Tubj1hooFxCl52G4qQu0edzV/+EZzPUeN8p2NnW5uu4fbDs+Yo7+qDVDc4/oG3FbCqEBmu/OC3LSsyiU22oghw==", + "version": "28.8.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.1.tgz", + "integrity": "sha512-G46XMyYu6PtSNJUkQ0hsPjzXYpzq/O4vpCciMizTKRJG8kNsRreGoMRDG6H9FIB/xVgfFuclVnuX4XRvFUzrZQ==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -9462,9 +9462,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { "braces": "^3.0.3", @@ -14375,9 +14375,9 @@ } }, "node_modules/winston": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.1.tgz", - "integrity": "sha512-SvZit7VFNvXRzbqGHsv5KSmgbEYR5EiQfDAL9gxYkRqa934Hnk++zze0wANKtMHcy/gI4W/3xmSDwlhf865WGw==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.14.2.tgz", + "integrity": "sha512-CO8cdpBB2yqzEf8v895L+GNKYJiEq8eKlHU38af3snQBQ+sdAIUepjMSguOIJC7ICbzm0ZI+Af2If4vIJrtmOg==", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", diff --git a/package.json b/package.json index a0679856..a0fd9302 100644 --- a/package.json +++ b/package.json @@ -107,17 +107,17 @@ "@hapi/vision": "7.0.3", "@mojaloop/central-services-error-handling": "13.0.1", "@mojaloop/central-services-health": "15.0.0", - "@mojaloop/central-services-logger": "11.5.0", + "@mojaloop/central-services-logger": "11.5.1", "@mojaloop/central-services-metrics": "12.0.8", "@mojaloop/central-services-shared": "18.5.0-snapshot.2", "@mojaloop/central-services-stream": "11.3.1", "@mojaloop/event-sdk": "14.1.1", - "@mojaloop/inter-scheme-proxy-cache-lib": "2.2.0", + "@mojaloop/inter-scheme-proxy-cache-lib": "2.3.0", "@mojaloop/ml-number": "11.2.4", "@mojaloop/sdk-standard-components": "18.1.0", "ajv": "8.17.1", "ajv-keywords": "5.1.0", - "axios": "1.7.4", + "axios": "1.7.5", "blipp": "4.0.2", "commander": "12.1.0", "event-stream": "4.0.1", @@ -138,7 +138,7 @@ "audit-ci": "^7.1.0", "eslint": "8.16.0", "eslint-config-standard": "17.1.0", - "eslint-plugin-jest": "28.8.0", + "eslint-plugin-jest": "28.8.1", "jest": "29.7.0", "jest-junit": "16.0.0", "npm-check-updates": "17.1.0", diff --git a/src/model/fxQuotes.js b/src/model/fxQuotes.js index 47d1c196..164a0df5 100644 --- a/src/model/fxQuotes.js +++ b/src/model/fxQuotes.js @@ -231,7 +231,7 @@ class FxQuotesModel { histTimer({ success: false, queryName: 'handleFxQuoteRequest' }) this.log.error('error in handleFxQuoteRequest', err) if (txn) { - txn.rollback(err) + await txn.rollback().catch(() => {}) } await this.handleException(fspiopSource, fxQuoteRequest.conversionRequestId, err, headers, childSpan) } finally { @@ -380,7 +380,7 @@ class FxQuotesModel { this.log.error('error in handleFxQuoteUpdate', err) const fspiopSource = headers[ENUM.Http.Headers.FSPIOP.SOURCE] if (txn) { - txn.rollback(err) + await txn.rollback().catch(() => {}) } await this.handleException(fspiopSource, conversionRequestId, err, headers, childSpan) } finally { @@ -534,7 +534,7 @@ class FxQuotesModel { }) // commit the txn to the db - txn.commit() + await txn.commit() } await childSpan.audit({ headers, params: { conversionRequestId } }, EventSdk.AuditEventAction.start) @@ -545,7 +545,7 @@ class FxQuotesModel { histTimer({ success: false, queryName: 'handleFxQuoteError' }) this.log.error('error in handleFxQuoteError', err) if (txn) { - txn.rollback(err) + await txn.rollback().catch(() => {}) } await this.handleException(fspiopSource, conversionRequestId, err, headers, childSpan) } finally { diff --git a/src/model/quotes.js b/src/model/quotes.js index 3ba51f90..71b02c7b 100644 --- a/src/model/quotes.js +++ b/src/model/quotes.js @@ -408,7 +408,7 @@ class QuotesModel { // internal-error this.writeLog(`Error in handleQuoteRequest for quoteId ${quoteRequest.quoteId}: ${getStackOrInspect(err)}`) if (txn) { - txn.rollback(err) + await txn.rollback().catch(() => {}) } const fspiopError = ErrorHandler.ReformatFSPIOPError(err) @@ -708,7 +708,7 @@ class QuotesModel { // internal-error this.writeLog(`Error in handleQuoteUpdate: ${getStackOrInspect(err)}`) if (txn) { - txn.rollback(err) + await txn.rollback().catch(() => {}) } const fspiopError = ErrorHandler.ReformatFSPIOPError(err) const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message) @@ -859,7 +859,7 @@ class QuotesModel { }) // commit the txn to the db - txn.commit() + await txn.commit() } // create a new object to represent the error const fspiopError = ErrorHandler.CreateFSPIOPErrorFromErrorInformation(error) @@ -873,7 +873,7 @@ class QuotesModel { // internal-error this.writeLog(`Error in handleQuoteError: ${getStackOrInspect(err)}`) if (txn) { - txn.rollback(err) + await txn.rollback().catch(() => {}) } const fspiopError = ErrorHandler.ReformatFSPIOPError(err) const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message) @@ -1000,8 +1000,9 @@ class QuotesModel { const childSpan = span.getChild('qs_quote_sendErrorCallback') try { await childSpan.audit({ headers, params: { quoteId } }, EventSdk.AuditEventAction.start) + const result = await this.sendErrorCallback(fspiopSource, fspiopError, quoteId, headers, childSpan, true) histTimer({ success: true, queryName: 'quote_handleException' }) - return await this.sendErrorCallback(fspiopSource, fspiopError, quoteId, headers, childSpan, true) + return result } catch (err) { // any-error // not much we can do other than log the error From 3ebd8289d77c5ac9564c7c37894da2df996ebda9 Mon Sep 17 00:00:00 2001 From: Kalin Krustev Date: Fri, 30 Aug 2024 10:25:31 +0000 Subject: [PATCH 2/2] test: fix mock --- test/unit/mocks.js | 2 +- test/unit/model/quotes.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/mocks.js b/test/unit/mocks.js index 2c4651eb..7c97da1c 100644 --- a/test/unit/mocks.js +++ b/test/unit/mocks.js @@ -118,7 +118,7 @@ const fxQuoteMocks = { }), db: ({ commit = jest.fn().mockResolvedValue({}), - rollback = jest.fn(), + rollback = jest.fn(() => Promise.reject(new Error('DB error'))), getParticipant = jest.fn().mockResolvedValue({}), getParticipantEndpoint = jest.fn().mockResolvedValue(undefined), createFxQuoteResponse = jest.fn().mockResolvedValue({}), diff --git a/test/unit/model/quotes.test.js b/test/unit/model/quotes.test.js index 43fda723..7ae814a8 100644 --- a/test/unit/model/quotes.test.js +++ b/test/unit/model/quotes.test.js @@ -124,7 +124,7 @@ describe('QuotesModel', () => { }) mockTransaction = { commit: jest.fn(), - rollback: jest.fn() + rollback: jest.fn(() => Promise.reject(new Error('DB error'))) } mockChildSpan = { injectContextToHttpRequest: jest.fn(opts => opts),