Skip to content

Commit 43440aa

Browse files
committed
fix: release tokens as soon as they are available
1 parent 7c3371b commit 43440aa

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

src/dialer/dial-request.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,21 @@ class DialRequest {
4747
const tokenHolder = new FIFO()
4848
tokens.forEach(token => tokenHolder.push(token))
4949
const dialAbortControllers = this.addrs.map(() => new AbortController())
50-
let completedDials = 0
50+
let startedDials = 0
5151

5252
try {
5353
return await pAny(this.addrs.map(async (addr, i) => {
5454
const token = await tokenHolder.shift() // get token
55+
startedDials++
5556
let conn
5657
try {
5758
const signal = dialAbortControllers[i].signal
5859
conn = await this.dialAction(addr, { ...options, signal: anySignal([signal, options.signal]) })
5960
// Remove the successful AbortController so it is not aborted
6061
dialAbortControllers.splice(i, 1)
6162
} finally {
62-
completedDials++
6363
// If we have more dials to make, recycle the token, otherwise release it
64-
if (completedDials < this.addrs.length) {
64+
if (startedDials < this.addrs.length) {
6565
tokenHolder.push(token)
6666
} else {
6767
this.dialer.releaseToken(tokens.splice(tokens.indexOf(token), 1)[0])

test/dialing/dial-request.spec.js

+49
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const { AbortError } = require('libp2p-interfaces/src/transport/errors')
1111
const AbortController = require('abort-controller')
1212
const AggregateError = require('aggregate-error')
1313
const pDefer = require('p-defer')
14+
const delay = require('delay')
1415

1516
const { DialRequest } = require('../../src/dialer/dial-request')
1617
const createMockConnection = require('../utils/mockConnection')
@@ -50,6 +51,54 @@ describe('Dial Request', () => {
5051
expect(dialer.releaseToken).to.have.property('callCount', tokens.length)
5152
})
5253

54+
it('should release tokens when all addr dials have started', async () => {
55+
const mockConnection = await createMockConnection()
56+
const deferred = pDefer()
57+
const actions = {
58+
1: async () => {
59+
await delay(0)
60+
return Promise.reject(error)
61+
},
62+
2: async () => {
63+
await delay(0)
64+
return Promise.reject(error)
65+
},
66+
3: () => deferred.promise
67+
}
68+
const dialAction = (num) => actions[num]()
69+
const tokens = ['a', 'b']
70+
const controller = new AbortController()
71+
const dialer = {
72+
getTokens: () => [...tokens],
73+
releaseToken: () => {}
74+
}
75+
76+
const dialRequest = new DialRequest({
77+
addrs: Object.keys(actions),
78+
dialer,
79+
dialAction
80+
})
81+
82+
sinon.spy(actions, 1)
83+
sinon.spy(actions, 2)
84+
sinon.spy(actions, 3)
85+
sinon.spy(dialer, 'releaseToken')
86+
dialRequest.run({ signal: controller.signal })
87+
// Let the first dials run
88+
await delay(10)
89+
90+
// Only 1 dial should remain, so 1 token should have been released
91+
expect(actions[1]).to.have.property('callCount', 1)
92+
expect(actions[2]).to.have.property('callCount', 1)
93+
expect(actions[3]).to.have.property('callCount', 1)
94+
expect(dialer.releaseToken).to.have.property('callCount', 1)
95+
96+
// Finish the dial
97+
deferred.resolve(mockConnection)
98+
await delay(0)
99+
expect(dialer.releaseToken).to.have.property('callCount', 2)
100+
})
101+
53102
it('should throw an AggregateError if all dials fail', async () => {
54103
const actions = {
55104
1: () => Promise.reject(error),

0 commit comments

Comments
 (0)