@toa.io/core 1.0.0-alpha.239 → 1.0.0-alpha.243
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/package.json +2 -2
- package/src/connector.js +6 -2
- package/src/discovery.js +13 -4
- package/test/connector.fixtures.js +8 -0
- package/test/connector.test.js +20 -0
- package/test/discovery.test.js +56 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/core",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.243",
|
|
4
4
|
"description": "Toa Core",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
"openspan": "1.0.0-alpha.173",
|
|
28
28
|
"uuid": "11.1.1"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "743e8060d35ca750f70487c04aef9698591c5edd"
|
|
31
31
|
}
|
package/src/connector.js
CHANGED
|
@@ -110,7 +110,11 @@ class Connector {
|
|
|
110
110
|
* @returns {Promise<void>}
|
|
111
111
|
*/
|
|
112
112
|
async disconnect (interrupt) {
|
|
113
|
-
|
|
113
|
+
// a connector that has not finished connecting has nothing to close, and
|
|
114
|
+
// awaiting a connection that may never settle outlives any grace period
|
|
115
|
+
const pending = interrupt === true || this.connected === false
|
|
116
|
+
|
|
117
|
+
if (!pending) await this.#connecting
|
|
114
118
|
|
|
115
119
|
if (this.#disconnecting) return this.#disconnecting
|
|
116
120
|
|
|
@@ -131,7 +135,7 @@ class Connector {
|
|
|
131
135
|
console.warn(`Connector ${this.id} still disconnecting (${delay})`)
|
|
132
136
|
}, DELAY)
|
|
133
137
|
|
|
134
|
-
if (
|
|
138
|
+
if (!pending) await this.close()
|
|
135
139
|
|
|
136
140
|
clearInterval(interval)
|
|
137
141
|
|
package/src/discovery.js
CHANGED
|
@@ -25,17 +25,26 @@ class Discovery extends Connector {
|
|
|
25
25
|
this.depends(this.#lookups[id])
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const since = Date.now()
|
|
29
|
+
|
|
30
|
+
// the wait is unbounded by design, as a dependency may still be starting,
|
|
31
|
+
// so repeating is the only way a component stuck on one stays visible
|
|
32
|
+
const warning = setInterval(() => {
|
|
33
|
+
const waiting = Math.round((Date.now() - since) / 1000)
|
|
34
|
+
|
|
35
|
+
console.warn('Waiting for lookup response', { component: id, waiting })
|
|
36
|
+
}, INTERVAL)
|
|
37
|
+
|
|
38
|
+
warning.unref()
|
|
30
39
|
|
|
31
40
|
const output = await this.#lookups[id].invoke()
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
clearInterval(warning)
|
|
34
43
|
|
|
35
44
|
return output
|
|
36
45
|
}
|
|
37
46
|
}
|
|
38
47
|
|
|
39
|
-
const
|
|
48
|
+
const INTERVAL = 5000
|
|
40
49
|
|
|
41
50
|
exports.Discovery = Discovery
|
|
@@ -36,5 +36,13 @@ class FailingConnector extends Connector {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/** Stands for a connector waiting for something that never arrives. */
|
|
40
|
+
class StuckConnector extends Connector {
|
|
41
|
+
async open () {
|
|
42
|
+
return new Promise(() => undefined)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
39
46
|
exports.TestConnector = TestConnector
|
|
40
47
|
exports.FailingConnector = FailingConnector
|
|
48
|
+
exports.StuckConnector = StuckConnector
|
package/test/connector.test.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { timeout } = require('@toa.io/generic')
|
|
4
|
+
|
|
3
5
|
const fixtures = require('./connector.fixtures')
|
|
4
6
|
|
|
5
7
|
let sequence
|
|
@@ -105,6 +107,7 @@ describe('dependencies', () => {
|
|
|
105
107
|
a.depends(b).depends(c)
|
|
106
108
|
b.depends(d)
|
|
107
109
|
|
|
110
|
+
await a.connect()
|
|
108
111
|
await a.disconnect()
|
|
109
112
|
|
|
110
113
|
expect(sequence.indexOf('-a')).toBeLessThan(sequence.indexOf('-b'))
|
|
@@ -146,6 +149,23 @@ describe('dependencies', () => {
|
|
|
146
149
|
expect(() => a.depends({})).toThrow()
|
|
147
150
|
})
|
|
148
151
|
|
|
152
|
+
it('should disconnect while still connecting', async () => {
|
|
153
|
+
const stuck = new fixtures.StuckConnector()
|
|
154
|
+
|
|
155
|
+
a.depends(stuck).depends(b)
|
|
156
|
+
|
|
157
|
+
void a.connect()
|
|
158
|
+
|
|
159
|
+
while (b.connected !== true) await timeout(1)
|
|
160
|
+
|
|
161
|
+
// `a` never connects, and disconnecting must not wait for it to
|
|
162
|
+
expect(a.connected).toStrictEqual(false)
|
|
163
|
+
|
|
164
|
+
await a.disconnect()
|
|
165
|
+
|
|
166
|
+
expect(sequence).toEqual(['+b', '-b', '*b', '*a'])
|
|
167
|
+
})
|
|
168
|
+
|
|
149
169
|
describe('errors', () => {
|
|
150
170
|
let f
|
|
151
171
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { console } = require('openspan')
|
|
4
|
+
const { Connector } = require('../src/connector')
|
|
5
|
+
const { Discovery } = require('../src/discovery')
|
|
6
|
+
|
|
7
|
+
class Lookup extends Connector {
|
|
8
|
+
invoke = jest.fn(async () => ({ operations: {} }))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** @type {Lookup} */
|
|
12
|
+
let lookup
|
|
13
|
+
|
|
14
|
+
/** @type {Discovery} */
|
|
15
|
+
let discovery
|
|
16
|
+
|
|
17
|
+
/** @type {jest.SpyInstance} */
|
|
18
|
+
let warn
|
|
19
|
+
|
|
20
|
+
const locator = { id: 'dummies.one' }
|
|
21
|
+
|
|
22
|
+
beforeEach(async () => {
|
|
23
|
+
jest.useFakeTimers()
|
|
24
|
+
|
|
25
|
+
warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined)
|
|
26
|
+
lookup = new Lookup()
|
|
27
|
+
discovery = new Discovery(async () => lookup)
|
|
28
|
+
|
|
29
|
+
await discovery.connect()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
warn.mockRestore()
|
|
34
|
+
jest.useRealTimers()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should not warn if a lookup is answered', async () => {
|
|
38
|
+
await discovery.lookup(locator)
|
|
39
|
+
|
|
40
|
+
jest.advanceTimersByTime(60_000)
|
|
41
|
+
|
|
42
|
+
expect(warn).not.toHaveBeenCalled()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should keep warning while a lookup is unanswered', async () => {
|
|
46
|
+
lookup.invoke.mockImplementation(() => new Promise(() => undefined))
|
|
47
|
+
|
|
48
|
+
void discovery.lookup(locator)
|
|
49
|
+
|
|
50
|
+
await jest.advanceTimersByTimeAsync(12_000)
|
|
51
|
+
|
|
52
|
+
expect(warn).toHaveBeenCalledTimes(2)
|
|
53
|
+
|
|
54
|
+
expect(warn).toHaveBeenLastCalledWith('Waiting for lookup response',
|
|
55
|
+
{ component: locator.id, waiting: 10 })
|
|
56
|
+
})
|