Skip to content
Permalink
Browse files

fix(lnd): force kill lnd after failed graceful shutdown

  • Loading branch information...
mrfelton committed Apr 19, 2019
1 parent 5f6faf2 commit dbe715b42fbe95850bf5448aa26c3e57348dcd23
Showing with 46 additions and 30 deletions.
  1. +4 −19 renderer/reducers/app.js
  2. +2 −7 renderer/reducers/neutrino.js
  3. +39 −4 services/neutrino/neutrino.js
  4. +1 −0 test/unit/lnd/neutrino.spec.js
@@ -1,10 +1,9 @@
import delay from '@zap/utils/delay'
import { send } from 'redux-electron-ipc'
import { createSelector } from 'reselect'
import { proxyValue } from 'comlinkjs'
import { neutrinoService, lightningService, walletUnlockerService } from 'workers'
import { tickerSelectors } from './ticker'
import { walletSelectors } from './wallet'
import { stopLnd } from './lnd'

// ------------------------------------
// Initial State
@@ -63,24 +62,10 @@ export const initApp = () => async (dispatch, getState) => {
export const terminateApp = (event, handler) => async dispatch => {
dispatch({ type: TERMINATE_APP })

// Disconnect gRPC streams.
const walletUnlocker = await walletUnlockerService
if (await walletUnlocker.can('disconnect')) {
await walletUnlocker.disconnect()
}
const lightning = await lightningService
if (await lightning.can('disconnect')) {
await lightning.disconnect()
}
// Shutdown lnd before terminating.
await dispatch(stopLnd())

// Kill active neutrino process before terminating.
const neutrino = await neutrinoService
if (await neutrino.getPid()) {
neutrino.once('NEUTRINO_EXIT', proxyValue(() => dispatch(terminateAppSuccess(handler))))
await neutrino.kill()
} else {
dispatch(terminateAppSuccess(handler))
}
dispatch(terminateAppSuccess(handler))
}

export const terminateAppSuccess = handler => async dispatch => {
@@ -138,13 +138,8 @@ export const stopNeutrino = () => async dispatch => {
dispatch({ type: STOP_NEUTRINO })
try {
const neutrino = await neutrinoService
await neutrino.kill()
neutrino.once(
'NEUTRINO_EXIT',
proxyValue(() => {
dispatch(stopNeutrinoSuccess())
})
)
await neutrino.shutdown()
dispatch(stopNeutrinoSuccess())
} catch (e) {
dispatch(stopNeutrinoFailure(e))
}
@@ -74,10 +74,8 @@ class Neutrino extends EventEmitter {
* @return {Number} PID of the Lnd process that was started.
*/
async start() {
if (this.process) {
return Promise.reject(
new Error(`Neutrino process with PID ${this.process.pid} already exists.`)
)
if (this.getPid()) {
return Promise.reject(new Error(`Neutrino process with PID ${this.getPid()} already exists.`))
}

// The height returned from the LND log output may not be the actual current block height (this is the case
@@ -279,6 +277,43 @@ class Neutrino extends EventEmitter {
return this.process.pid
}

/**
* Gracefully shutdown LND.
*/
async shutdown(options = {}) {
const signal = options.signal || 'SIGINT'
const timeout = options.timeout || 10000

mainLog.info('Shutting down Neutrino...')

if (!this.getPid()) {
mainLog.info('No Neutrino process found.')
return
}

await new Promise(async resolve => {
// HACK: Sometimes there are errors during the shutdown process that prevent the daemon from shutting down at
// all. If we haven't received notification of the process closing within the timeout, kill it.
// See https://github.com/lightningnetwork/lnd/pull/1781
// See https://github.com/lightningnetwork/lnd/pull/1783
const exitHandler = () => {
clearTimeout(shutdownTimeout)
resolve()
}
const shutdownTimeout = setTimeout(() => {
mainLog.warn('Graceful shutdown failed to complete within 10 seconds. Killing Neutrino.')
this.kill('SIGKILL')
}, timeout)

this.once('NEUTRINO_EXIT', exitHandler)

// Kill the Neutrino process (sends SIGINT to Neutrino process)
this.kill(signal)
})

mainLog.info('Neutrino shutdown complete.')
}

/**
* Stop the Lnd process.
*/
@@ -211,6 +211,7 @@ describe('Neutrino', function() {
beforeEach(async () => {
this.neutrino = await prepareLndConfig(lndConfigOptions)
this.neutrino.process = mockSpawn()
this.neutrino.process.pid = 123
})
it('should throw an error', async () => {
await expect(this.neutrino.start()).rejects.toThrowErrorMatchingInlineSnapshot(

0 comments on commit dbe715b

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