Skip to content
Permalink
Browse files

fix(grpc): setup channel graph stream after sync

If we fail to subscribe to the channel graph after initial sync has
completed keep retrying until we get a successful connection.

Fix #2226
  • Loading branch information...
mrfelton committed May 17, 2019
1 parent 8a498ef commit 5c930d780081e176f625c2509238b96ff28a87d9
Showing with 41 additions and 5 deletions.
  1. +41 −5 services/grpc/grpc.js
@@ -4,6 +4,7 @@ import { proxyValue } from 'comlinkjs'
import { status } from '@grpc/grpc-js'
import LndGrpc from 'lnd-grpc'
import { grpcLog } from '@zap/utils/log'
import delay from '@zap/utils/delay'
import lightningMethods from './lightning.methods'
import lightningSubscriptions from './lightning.subscriptions'
import { forwardAll, unforwardAll } from './helpers'
@@ -104,14 +105,13 @@ class ZapGrpc extends EventEmitter {
subscribeAll() {
this.subscribe('invoices', 'transactions', 'info')

// subscribe to graph updates only after sync is complete
// this is needed because LND chanRouter waits for chain sync
// to complete before accepting subscriptions.
this.on('subscribeGetInfo.data', data => {
// Subscribe to graph updates only after sync is complete. This is needed because LND chanRouter waits for chain
// sync to complete before accepting subscriptions.
this.on('subscribeGetInfo.data', async data => {
const { synced_to_chain } = data
if (synced_to_chain && !this.activeSubscriptions.channelgraph) {
this.subscribe('channelgraph')
this.unsubscribe('info')
this.subscribeChannelGraph()
}
})
}
@@ -248,6 +248,42 @@ class ZapGrpc extends EventEmitter {

return { host, cert, macaroon, waitForMacaroon, waitForCert, useMacaroon, protoDir }
}

/**
* async subscribeChannelGraph - Set up subscription to the channel graph stream.
*
* There is no guarentee that it is ready yet as it can take time for lnd to start it once chain sync has finished
* so set up a schedular to keep retrying until it works.
*/
subscribeChannelGraph() {
const backoff = 2
const maxTimeout = 1000 * 60
let timeout = 250

const initSubscription = async () => {
if (this.grpc.state !== 'active') {
return
}

this.subscribe('channelgraph')

// If the channel graph subscription fails to start, try again in a bit.
if (this.activeSubscriptions.channelgraph) {
this.activeSubscriptions.channelgraph.once('error', async error => {
if (error.message === 'router not started') {
grpcLog.warn('Unable to subscribe to channelgraph. Will try again in %sms', timeout)
await delay(timeout)
initSubscription()
if (timeout <= maxTimeout) {
timeout = Math.min(timeout * backoff, maxTimeout)
}
}
})
}
}

initSubscription()
}
}

export default ZapGrpc

0 comments on commit 5c930d7

Please sign in to comment.
You can’t perform that action at this time.