account-lookup-service 17.10.2 → 17.11.0-snapshot.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/config/default.json +14 -1
- package/docker/account-lookup-service/default.json +18 -3
- package/docker-compose.yml +2 -0
- package/package.json +6 -5
- package/src/constants.js +4 -1
- package/src/domain/parties/services/BasePartiesService.js +9 -3
- package/src/domain/parties/services/TimeoutPartiesService.js +1 -1
- package/src/handlers/TimeoutHandler.js +9 -3
- package/src/handlers/register.js +1 -1
- package/src/lib/config.js +1 -0
- package/src/lib/createDistLock.js +74 -0
- package/src/lib/index.js +3 -1
- package/test/integration/domain/timeout/index.test.js +12 -8
- package/test/unit/handlers/TimeoutHandler.test.js +58 -4
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
4
4
|
|
5
|
+
### [17.10.3](https://github.com/mojaloop/account-lookup-service/compare/v17.10.2...v17.10.3) (2025-06-24)
|
6
|
+
|
7
|
+
|
8
|
+
### Bug Fixes
|
9
|
+
|
10
|
+
* ensure timeout callbacks have content-type headers ([#555](https://github.com/mojaloop/account-lookup-service/issues/555)) ([3850241](https://github.com/mojaloop/account-lookup-service/commit/38502419d1900e5ccef869ddde07274974efb62d))
|
11
|
+
|
5
12
|
### [17.10.2](https://github.com/mojaloop/account-lookup-service/compare/v17.10.1...v17.10.2) (2025-06-23)
|
6
13
|
|
7
14
|
|
package/config/default.json
CHANGED
@@ -80,7 +80,20 @@
|
|
80
80
|
"DISABLED": false,
|
81
81
|
"TIMEXP": "*/30 * * * * *",
|
82
82
|
"TIMEZONE": "UTC",
|
83
|
-
"BATCH_SIZE": 100
|
83
|
+
"BATCH_SIZE": 100,
|
84
|
+
"DIST_LOCK": {
|
85
|
+
"enabled": false,
|
86
|
+
"lockTimeout": 10000,
|
87
|
+
"acquireTimeout": 5000,
|
88
|
+
"driftFactor": 0.01,
|
89
|
+
"retryCount": 3,
|
90
|
+
"retryDelay": 200,
|
91
|
+
"retryJitter": 100,
|
92
|
+
"redisConfigs": [{
|
93
|
+
"type": "redis-cluster",
|
94
|
+
"cluster": [{ "host": "localhost", "port": 6379 }]
|
95
|
+
}]
|
96
|
+
}
|
84
97
|
}
|
85
98
|
},
|
86
99
|
"SWITCH_ENDPOINT": "http://localhost:3001",
|
@@ -24,15 +24,18 @@
|
|
24
24
|
},
|
25
25
|
"PROTOCOL_VERSIONS": {
|
26
26
|
"CONTENT": {
|
27
|
-
"DEFAULT": "
|
27
|
+
"DEFAULT": "2.0",
|
28
28
|
"VALIDATELIST": [
|
29
|
+
"2.0",
|
29
30
|
"1.1",
|
30
31
|
"1.0"
|
31
32
|
]
|
32
33
|
},
|
33
34
|
"ACCEPT": {
|
34
|
-
"DEFAULT": "
|
35
|
+
"DEFAULT": "2",
|
35
36
|
"VALIDATELIST": [
|
37
|
+
"2",
|
38
|
+
"2.0",
|
36
39
|
"1",
|
37
40
|
"1.0",
|
38
41
|
"1.1"
|
@@ -76,7 +79,19 @@
|
|
76
79
|
"DISABLED": false,
|
77
80
|
"TIMEXP": "*/10 * * * * *",
|
78
81
|
"TIMEZONE": "UTC",
|
79
|
-
"BATCH_SIZE": 100
|
82
|
+
"BATCH_SIZE": 100,
|
83
|
+
"DIST_LOCK": {
|
84
|
+
"enabled": true,
|
85
|
+
"lockTimeout": 10000,
|
86
|
+
"driftFactor": 0.01,
|
87
|
+
"retryCount": 3,
|
88
|
+
"retryDelay": 200,
|
89
|
+
"retryJitter": 100,
|
90
|
+
"redisConfigs": [{
|
91
|
+
"type": "redis-cluster",
|
92
|
+
"cluster": [{ "host": "redis-node-0", "port": 6379 }]
|
93
|
+
}]
|
94
|
+
}
|
80
95
|
}
|
81
96
|
},
|
82
97
|
"SWITCH_ENDPOINT": "http://central-ledger:3001",
|
package/docker-compose.yml
CHANGED
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "account-lookup-service",
|
3
3
|
"description": "Account Lookup Service is used to validate Party and Participant lookups.",
|
4
|
-
"version": "17.
|
4
|
+
"version": "17.11.0-snapshot.0",
|
5
5
|
"license": "Apache-2.0",
|
6
6
|
"author": "ModusBox",
|
7
7
|
"contributors": [
|
@@ -68,6 +68,7 @@
|
|
68
68
|
"seed:run": "knex seed:run $npm_package_config_knex",
|
69
69
|
"seed:create": "knex seed:make $npm_package_config_knex",
|
70
70
|
"regenerate": "yo swaggerize:test --framework hapi --apiPath './config/api_swagger.json'",
|
71
|
+
"dc:up:als-toh": ". ./test/integration/env.sh && docker compose $npm_package_config_env_file up account-lookup-service-handlers",
|
71
72
|
"dc:build": "docker compose $npm_package_config_env_file build",
|
72
73
|
"dc:up": ". ./test/integration/env.sh && docker compose $npm_package_config_env_file up -d && docker ps",
|
73
74
|
"dc:down": ". ./test/integration/env.sh && docker compose $npm_package_config_env_file down -v",
|
@@ -94,13 +95,13 @@
|
|
94
95
|
"@mojaloop/central-services-health": "15.1.0",
|
95
96
|
"@mojaloop/central-services-logger": "11.9.0",
|
96
97
|
"@mojaloop/central-services-metrics": "12.6.0",
|
97
|
-
"@mojaloop/central-services-shared": "18.
|
98
|
-
"@mojaloop/central-services-stream": "11.
|
98
|
+
"@mojaloop/central-services-shared": "18.29.0-snapshot.0",
|
99
|
+
"@mojaloop/central-services-stream": "11.8.0",
|
99
100
|
"@mojaloop/database-lib": "11.2.0",
|
100
101
|
"@mojaloop/event-sdk": "14.6.1",
|
101
102
|
"@mojaloop/inter-scheme-proxy-cache-lib": "2.6.0",
|
102
103
|
"@mojaloop/ml-schema-transformer-lib": "2.7.1",
|
103
|
-
"@mojaloop/sdk-standard-components": "19.
|
104
|
+
"@mojaloop/sdk-standard-components": "19.16.0",
|
104
105
|
"@now-ims/hapi-now-auth": "2.1.0",
|
105
106
|
"ajv": "8.17.1",
|
106
107
|
"ajv-keywords": "5.1.0",
|
@@ -165,7 +166,7 @@
|
|
165
166
|
"axios": "1.10.0",
|
166
167
|
"axios-retry": "^4.5.0",
|
167
168
|
"docdash": "2.0.2",
|
168
|
-
"dotenv": "^
|
169
|
+
"dotenv": "^17.0.1",
|
169
170
|
"get-port": "5.1.1",
|
170
171
|
"ioredis-mock": "^8.9.0",
|
171
172
|
"jest": "29.7.0",
|
package/src/constants.js
CHANGED
@@ -43,8 +43,11 @@ const HANDLER_TYPES = Object.freeze({
|
|
43
43
|
TIMEOUT: 'timeout'
|
44
44
|
})
|
45
45
|
|
46
|
+
const TIMEOUT_HANDLER_DIST_LOCK_KEY = 'mutex:als-timeout-handler'
|
47
|
+
|
46
48
|
module.exports = {
|
47
49
|
API_TYPES,
|
48
50
|
ERROR_MESSAGES,
|
49
|
-
HANDLER_TYPES
|
51
|
+
HANDLER_TYPES,
|
52
|
+
TIMEOUT_HANDLER_DIST_LOCK_KEY
|
50
53
|
}
|
@@ -31,9 +31,10 @@ const { decodePayload } = require('@mojaloop/central-services-shared').Util.Stre
|
|
31
31
|
const { initStepState } = require('../../../lib/util')
|
32
32
|
const { createCallbackHeaders } = require('../../../lib/headers')
|
33
33
|
const { ERROR_MESSAGES } = require('../../../constants')
|
34
|
+
const { makeAcceptContentTypeHeader } = require('@mojaloop/central-services-shared').Util.Headers
|
34
35
|
|
35
36
|
const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
|
36
|
-
const { Headers, RestMethods } = Enum.Http
|
37
|
+
const { Headers, RestMethods, HeaderResources } = Enum.Http
|
37
38
|
|
38
39
|
/**
|
39
40
|
* @typedef {Object} PartiesDeps
|
@@ -246,10 +247,15 @@ class BasePartiesService {
|
|
246
247
|
return cbHeaders
|
247
248
|
}
|
248
249
|
|
249
|
-
static createHubErrorCallbackHeaders (hubName, destination) {
|
250
|
+
static createHubErrorCallbackHeaders (hubName, destination, config) {
|
250
251
|
return {
|
251
252
|
[Headers.FSPIOP.SOURCE]: hubName,
|
252
|
-
[Headers.FSPIOP.DESTINATION]: destination
|
253
|
+
[Headers.FSPIOP.DESTINATION]: destination,
|
254
|
+
[Headers.GENERAL.CONTENT_TYPE.value]: makeAcceptContentTypeHeader(
|
255
|
+
HeaderResources.PARTIES,
|
256
|
+
config.PROTOCOL_VERSIONS.CONTENT.DEFAULT.toString(),
|
257
|
+
config.API_TYPE
|
258
|
+
)
|
253
259
|
}
|
254
260
|
}
|
255
261
|
|
@@ -41,7 +41,7 @@ class TimeoutPartiesService extends PutPartiesErrorService {
|
|
41
41
|
*/
|
42
42
|
static createInstance (deps, cacheKey, spanName) {
|
43
43
|
const { destination, partyType, partyId } = TimeoutPartiesService.parseExpiredKey(cacheKey)
|
44
|
-
const headers = TimeoutPartiesService.createHubErrorCallbackHeaders(deps.config.HUB_NAME, destination)
|
44
|
+
const headers = TimeoutPartiesService.createHubErrorCallbackHeaders(deps.config.HUB_NAME, destination, deps.config)
|
45
45
|
const params = { Type: partyType, ID: partyId } // todo: think, if we need to handle party SubId
|
46
46
|
const childSpan = createSpan(spanName, headers, params)
|
47
47
|
|
@@ -34,10 +34,12 @@ const CronJob = require('cron').CronJob
|
|
34
34
|
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
35
35
|
const TimeoutService = require('../domain/timeout')
|
36
36
|
const Config = require('../lib/config')
|
37
|
+
const { createDistLock } = require('../lib')
|
37
38
|
|
38
39
|
let timeoutJob
|
39
40
|
let isRegistered
|
40
41
|
let isRunning
|
42
|
+
let distLock
|
41
43
|
|
42
44
|
const timeout = async (options) => {
|
43
45
|
if (isRunning) return
|
@@ -45,24 +47,26 @@ const timeout = async (options) => {
|
|
45
47
|
|
46
48
|
try {
|
47
49
|
isRunning = true
|
50
|
+
if (!await distLock?.acquireLock()) return
|
48
51
|
await TimeoutService.timeoutInterschemePartiesLookups(options)
|
49
52
|
await TimeoutService.timeoutProxyGetPartiesLookups(options)
|
50
53
|
logger.verbose('ALS timeout handler is done')
|
51
54
|
} catch (err) {
|
52
55
|
logger.error('error in timeout: ', err)
|
53
56
|
} finally {
|
57
|
+
await distLock?.releaseLock()
|
54
58
|
isRunning = false
|
55
59
|
}
|
56
60
|
}
|
57
61
|
|
58
62
|
const register = async (options) => {
|
59
63
|
if (Config.HANDLERS_TIMEOUT_DISABLED) return false
|
60
|
-
|
61
64
|
const { logger } = options
|
62
65
|
|
63
66
|
try {
|
64
67
|
if (isRegistered) {
|
65
|
-
|
68
|
+
logger.info('Timeout handler already registered')
|
69
|
+
return false
|
66
70
|
}
|
67
71
|
timeoutJob = CronJob.from({
|
68
72
|
start: false,
|
@@ -70,6 +74,7 @@ const register = async (options) => {
|
|
70
74
|
cronTime: Config.HANDLERS_TIMEOUT_TIMEXP,
|
71
75
|
timeZone: Config.HANDLERS_TIMEOUT_TIMEZONE
|
72
76
|
})
|
77
|
+
distLock = createDistLock(Config.HANDLERS_TIMEOUT?.DIST_LOCK, logger)
|
73
78
|
timeoutJob.start()
|
74
79
|
isRegistered = true
|
75
80
|
logger.info('Timeout handler registered')
|
@@ -83,7 +88,8 @@ const register = async (options) => {
|
|
83
88
|
const stop = async () => {
|
84
89
|
if (isRegistered) {
|
85
90
|
await timeoutJob.stop()
|
86
|
-
|
91
|
+
// await distLock?.releaseLock()
|
92
|
+
isRegistered = false
|
87
93
|
}
|
88
94
|
}
|
89
95
|
|
package/src/handlers/register.js
CHANGED
@@ -70,7 +70,7 @@ const registerHandlers = async (handlers, options) => {
|
|
70
70
|
const registerAllHandlers = async (options) => {
|
71
71
|
options.logger.debug('Registering all handlers')
|
72
72
|
await init(options)
|
73
|
-
TimeoutHandler.register(options)
|
73
|
+
await TimeoutHandler.register(options)
|
74
74
|
}
|
75
75
|
|
76
76
|
const stopAllHandlers = async (options) => {
|
package/src/lib/config.js
CHANGED
@@ -162,6 +162,7 @@ const config = {
|
|
162
162
|
HANDLERS_TIMEOUT_TIMEXP: RC.HANDLERS.TIMEOUT.TIMEXP,
|
163
163
|
HANDLERS_TIMEOUT_TIMEZONE: RC.HANDLERS.TIMEOUT.TIMEZONE,
|
164
164
|
HANDLERS_TIMEOUT_BATCH_SIZE: RC.HANDLERS.TIMEOUT.BATCH_SIZE,
|
165
|
+
HANDLERS_TIMEOUT_DIST_LOCK_ENABLED: RC.HANDLERS.TIMEOUT?.DIST_LOCK?.enabled,
|
165
166
|
ERROR_HANDLING: RC.ERROR_HANDLING,
|
166
167
|
SWITCH_ENDPOINT: RC.SWITCH_ENDPOINT,
|
167
168
|
INSTRUMENTATION_METRICS_DISABLED: RC.INSTRUMENTATION.METRICS.DISABLED,
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
10
|
+
|
11
|
+
Contributors
|
12
|
+
--------------
|
13
|
+
This is the official list of the Mojaloop project contributors for this file.
|
14
|
+
Names of the original copyright holders (individuals or organizations)
|
15
|
+
should be listed with a '*' in the first column. People who have
|
16
|
+
contributed from an organization can be listed under the organization
|
17
|
+
that actually holds the copyright for their contributions (see the
|
18
|
+
Mojaloop Foundation for an example). Those individuals should have
|
19
|
+
their names indented and be marked with a '-'. Email address can be added
|
20
|
+
optionally within square brackets <email>.
|
21
|
+
|
22
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const { distLock } = require('@mojaloop/central-services-shared').Util
|
29
|
+
const { TIMEOUT_HANDLER_DIST_LOCK_KEY } = require('../constants')
|
30
|
+
|
31
|
+
const createDistLock = (distLockConfig, logger) => {
|
32
|
+
const distLockKey = TIMEOUT_HANDLER_DIST_LOCK_KEY
|
33
|
+
const distLockTtl = distLockConfig?.lockTimeout || 10000
|
34
|
+
const distLockAcquireTimeout = distLockConfig?.acquireTimeout || 5000
|
35
|
+
|
36
|
+
const lock = distLockConfig?.enabled
|
37
|
+
? distLock.createLock(distLockConfig, logger)
|
38
|
+
: null
|
39
|
+
|
40
|
+
const acquireLock = async () => {
|
41
|
+
if (lock) {
|
42
|
+
try {
|
43
|
+
return !!(await lock.acquire(distLockKey, distLockTtl, distLockAcquireTimeout))
|
44
|
+
} catch (err) {
|
45
|
+
logger.error('error acquiring distributed lock:', err)
|
46
|
+
// should this be added to metrics?
|
47
|
+
return false
|
48
|
+
}
|
49
|
+
}
|
50
|
+
logger.info('distributed lock not configured or disabled, running without distributed lock')
|
51
|
+
return true
|
52
|
+
}
|
53
|
+
|
54
|
+
const releaseLock = async () => {
|
55
|
+
if (lock) {
|
56
|
+
try {
|
57
|
+
await lock.release()
|
58
|
+
logger.verbose('distributed lock released')
|
59
|
+
} catch (error) {
|
60
|
+
logger.error('error releasing distributed lock:', error)
|
61
|
+
// should this be added to metrics?
|
62
|
+
}
|
63
|
+
} else {
|
64
|
+
logger.verbose('distributed lock not configured or disabled')
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
return {
|
69
|
+
acquireLock,
|
70
|
+
releaseLock
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
module.exports = createDistLock
|
package/src/lib/index.js
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
const { loggerFactory, asyncStorage } = require('@mojaloop/central-services-logger/src/contextLogger')
|
2
2
|
const { TransformFacades } = require('@mojaloop/ml-schema-transformer-lib')
|
3
|
+
const createDistLock = require('./createDistLock')
|
3
4
|
|
4
5
|
const logger = loggerFactory('ALS') // global logger without context
|
5
6
|
|
6
7
|
module.exports = {
|
7
8
|
logger,
|
8
9
|
asyncStorage,
|
9
|
-
TransformFacades
|
10
|
+
TransformFacades,
|
11
|
+
createDistLock
|
10
12
|
}
|
@@ -91,10 +91,12 @@ describe('Timeout Handler', () => {
|
|
91
91
|
expect(await checkKeysExistence(keys)).toEqual([0, 0])
|
92
92
|
|
93
93
|
expect(history.length).toBe(2)
|
94
|
-
const
|
95
|
-
const
|
96
|
-
expect(
|
97
|
-
expect(
|
94
|
+
const entry0 = history.find(h => h.path.includes(partyIds[0]))
|
95
|
+
const entry1 = history.find(h => h.path.includes(partyIds[1]))
|
96
|
+
expect(entry0.path).toBe(`/parties/${PARTY_ID_TYPE}/${partyIds[0]}/error`)
|
97
|
+
expect(entry1.path).toBe(`/parties/${PARTY_ID_TYPE}/${partyIds[1]}/error`)
|
98
|
+
expect(entry0.headers['content-type']).toContain('parties')
|
99
|
+
expect(entry1.headers['content-type']).toContain('parties')
|
98
100
|
})
|
99
101
|
|
100
102
|
it('should pass timeoutProxyGetPartiesLookups flow', async () => {
|
@@ -122,9 +124,11 @@ describe('Timeout Handler', () => {
|
|
122
124
|
expect(await checkKeysExistence(keys)).toEqual([0, 0])
|
123
125
|
|
124
126
|
expect(history.length).toBe(2)
|
125
|
-
const
|
126
|
-
const
|
127
|
-
expect(
|
128
|
-
expect(
|
127
|
+
const entry1 = history.find(h => h.path.includes(partyId1))
|
128
|
+
const entry2 = history.find(h => h.path.includes(partyId2))
|
129
|
+
expect(entry1.path).toBe(`/parties/${PARTY_ID_TYPE}/${partyId1}/error`)
|
130
|
+
expect(entry2.path).toBe(`/parties/${PARTY_ID_TYPE}/${partyId2}/error`)
|
131
|
+
expect(entry1.headers['content-type']).toContain('parties')
|
132
|
+
expect(entry2.headers['content-type']).toContain('parties')
|
129
133
|
})
|
130
134
|
})
|
@@ -31,11 +31,23 @@
|
|
31
31
|
|
32
32
|
'use strict'
|
33
33
|
|
34
|
+
let mockDistLock
|
35
|
+
jest.mock('@mojaloop/central-services-shared', () => ({
|
36
|
+
...jest.requireActual('@mojaloop/central-services-shared'),
|
37
|
+
Util: {
|
38
|
+
...jest.requireActual('@mojaloop/central-services-shared').Util,
|
39
|
+
distLock: {
|
40
|
+
createLock: jest.fn().mockImplementation(() => mockDistLock)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}))
|
44
|
+
|
34
45
|
const CronJob = require('cron').CronJob
|
35
46
|
const TimeoutHandler = require('../../../src/handlers/TimeoutHandler')
|
36
47
|
const TimeoutService = require('../../../src/domain/timeout')
|
37
48
|
const Config = require('../../../src/lib/config')
|
38
49
|
const { logger } = require('../../../src/lib')
|
50
|
+
|
39
51
|
const DefaultConfig = { ...Config }
|
40
52
|
|
41
53
|
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms))
|
@@ -48,8 +60,19 @@ describe('TimeoutHandler', () => {
|
|
48
60
|
start: jest.fn(),
|
49
61
|
stop: jest.fn()
|
50
62
|
})
|
51
|
-
const mockProxyCache = {
|
52
|
-
|
63
|
+
const mockProxyCache = {
|
64
|
+
processExpiredAlsKeys: jest.fn(),
|
65
|
+
processExpiredProxyGetPartiesKeys: jest.fn()
|
66
|
+
}
|
67
|
+
mockOptions = {
|
68
|
+
proxyCache: mockProxyCache,
|
69
|
+
batchSize: 10,
|
70
|
+
logger
|
71
|
+
}
|
72
|
+
mockDistLock = {
|
73
|
+
acquire: jest.fn().mockResolvedValue(true),
|
74
|
+
release: jest.fn().mockResolvedValue()
|
75
|
+
}
|
53
76
|
})
|
54
77
|
|
55
78
|
afterEach(async () => {
|
@@ -57,13 +80,20 @@ describe('TimeoutHandler', () => {
|
|
57
80
|
})
|
58
81
|
|
59
82
|
describe('timeout', () => {
|
83
|
+
afterEach(async () => {
|
84
|
+
await TimeoutHandler.stop()
|
85
|
+
})
|
86
|
+
|
60
87
|
it('should execute timout service', async () => {
|
88
|
+
await TimeoutHandler.register(mockOptions)
|
61
89
|
jest.spyOn(TimeoutService, 'timeoutInterschemePartiesLookups').mockResolvedValue()
|
62
|
-
await
|
90
|
+
await TimeoutHandler.timeout(mockOptions)
|
63
91
|
expect(TimeoutService.timeoutInterschemePartiesLookups).toHaveBeenCalled()
|
64
92
|
})
|
65
93
|
|
66
|
-
it('should not run if isRunning is true', async () => {
|
94
|
+
it('should not run if isRunning is true (distLock disabled)', async () => {
|
95
|
+
await TimeoutHandler.register(mockOptions)
|
96
|
+
Config.HANDLERS_TIMEOUT_DIST_LOCK_ENABLED = false
|
67
97
|
jest.spyOn(TimeoutService, 'timeoutInterschemePartiesLookups').mockImplementation(async () => {
|
68
98
|
await wait(1000)
|
69
99
|
})
|
@@ -73,6 +103,30 @@ describe('TimeoutHandler', () => {
|
|
73
103
|
])
|
74
104
|
expect(TimeoutService.timeoutInterschemePartiesLookups).toHaveBeenCalledTimes(1)
|
75
105
|
})
|
106
|
+
|
107
|
+
it('should use distributed lock when enabled', async () => {
|
108
|
+
Config.HANDLERS_TIMEOUT.DIST_LOCK = { enabled: true }
|
109
|
+
jest.spyOn(TimeoutService, 'timeoutProxyGetPartiesLookups').mockResolvedValue()
|
110
|
+
await TimeoutHandler.register(mockOptions)
|
111
|
+
|
112
|
+
await TimeoutHandler.timeout(mockOptions)
|
113
|
+
expect(mockDistLock.acquire).toHaveBeenCalledTimes(1)
|
114
|
+
expect(mockDistLock.release).toHaveBeenCalledTimes(1)
|
115
|
+
expect(TimeoutService.timeoutProxyGetPartiesLookups).toHaveBeenCalled()
|
116
|
+
})
|
117
|
+
|
118
|
+
it('should not run if distributed lock cannot be acquired', async () => {
|
119
|
+
mockDistLock.acquire = jest.fn().mockResolvedValue(false)
|
120
|
+
Config.HANDLERS_TIMEOUT.DIST_LOCK = { enabled: true }
|
121
|
+
jest.spyOn(TimeoutService, 'timeoutProxyGetPartiesLookups').mockResolvedValue()
|
122
|
+
await TimeoutHandler.register(mockOptions)
|
123
|
+
|
124
|
+
await TimeoutHandler.timeout(mockOptions)
|
125
|
+
|
126
|
+
expect(mockDistLock.acquire).toHaveBeenCalledTimes(1)
|
127
|
+
expect(mockDistLock.release).toHaveBeenCalled() // todo: think if we need .release() to have been called
|
128
|
+
expect(TimeoutService.timeoutProxyGetPartiesLookups).not.toHaveBeenCalled()
|
129
|
+
})
|
76
130
|
})
|
77
131
|
|
78
132
|
describe('register', () => {
|