Browse Source

add a retry mecanism on the open()

master
Gaëtan Renaudeau 7 years ago
parent
commit
4fb9e48483
  1. 9
      src/helpers/deviceAccess.js
  2. 27
      src/helpers/promise.js

9
src/helpers/deviceAccess.js

@ -1,7 +1,8 @@
// @flow
import createSemaphore from 'semaphore'
import type Transport from '@ledgerhq/hw-transport'
import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid'
import { retry } from './promise'
// all open to device must use openDevice so we can prevent race conditions
// and guarantee we do one device access at a time. It also will handle the .close()
@ -18,17 +19,19 @@ export const withDevice: WithDevice = devicePath => {
`deviceAccess is only expected to be used in process 'devices'. Any other usage may lead to race conditions. (Got: '${FORK_TYPE}')`,
)
}
const sem =
semaphorePerDevice[devicePath] || (semaphorePerDevice[devicePath] = createSemaphore(1))
return job =>
takeSemaphorePromise(sem, async () => {
const t = await CommNodeHid.open(devicePath)
const t = await retry(() => TransportNodeHid.open(devicePath))
try {
const res = await job(t)
// $FlowFixMe
return res
} finally {
t.close()
await t.close()
}
})
}

27
src/helpers/promise.js

@ -0,0 +1,27 @@
// @flow
// small utilities for Promises
export const delay = (ms: number): Promise<void> => new Promise(f => setTimeout(f, ms))
const defaults = {
maxRetry: 4,
interval: 300,
intervalMultiplicator: 1.5,
}
export function retry<A>(f: () => Promise<A>, options?: $Shape<typeof defaults>): Promise<A> {
const { maxRetry, interval, intervalMultiplicator } = { ...defaults, ...options }
return rec(maxRetry, interval)
function rec(remainingTry, interval) {
const result = f()
if (remainingTry <= 0) {
return result
}
// In case of failure, wait the interval, retry the action
return result.catch(() =>
delay(interval).then(() => rec(remainingTry - 1, interval * intervalMultiplicator)),
)
}
}
Loading…
Cancel
Save