Merge pull request #2522 from roeierez/cleanup_server_error
Cleanup in case of server failed to start
This commit is contained in:
commit
5d1574f566
@ -231,7 +231,7 @@ type ChainControl struct {
|
|||||||
// full-node, another backed by a running bitcoind full-node, and the other
|
// full-node, another backed by a running bitcoind full-node, and the other
|
||||||
// backed by a running neutrino light client instance. When running with a
|
// backed by a running neutrino light client instance. When running with a
|
||||||
// neutrino light client instance, `neutrinoCS` must be non-nil.
|
// neutrino light client instance, `neutrinoCS` must be non-nil.
|
||||||
func NewChainControl(cfg *Config) (*ChainControl, error) {
|
func NewChainControl(cfg *Config) (*ChainControl, func(), error) {
|
||||||
|
|
||||||
// Set the RPC config from the "home" chain. Multi-chain isn't yet
|
// Set the RPC config from the "home" chain. Multi-chain isn't yet
|
||||||
// active, so we'll restrict usage to a particular chain for now.
|
// active, so we'll restrict usage to a particular chain for now.
|
||||||
@ -269,7 +269,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
DefaultLitecoinStaticFeePerKW, 0,
|
DefaultLitecoinStaticFeePerKW, 0,
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("default routing policy for chain %v is "+
|
return nil, nil, fmt.Errorf("default routing policy for chain %v is "+
|
||||||
"unknown", cfg.PrimaryChain())
|
"unknown", cfg.PrimaryChain())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
heightHintCacheConfig, cfg.LocalChanDB,
|
heightHintCacheConfig, cfg.LocalChanDB,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to initialize height hint "+
|
return nil, nil, fmt.Errorf("unable to initialize height hint "+
|
||||||
"cache: %v", err)
|
"cache: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,14 +316,14 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
)
|
)
|
||||||
cc.ChainView, err = chainview.NewCfFilteredChainView(cfg.NeutrinoCS)
|
cc.ChainView, err = chainview.NewCfFilteredChainView(cfg.NeutrinoCS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the deprecated neutrino feeurl flag to the general fee
|
// Map the deprecated neutrino feeurl flag to the general fee
|
||||||
// url.
|
// url.
|
||||||
if cfg.NeutrinoMode.FeeURL != "" {
|
if cfg.NeutrinoMode.FeeURL != "" {
|
||||||
if cfg.FeeURL != "" {
|
if cfg.FeeURL != "" {
|
||||||
return nil, errors.New("feeurl and " +
|
return nil, nil, errors.New("feeurl and " +
|
||||||
"neutrino.feeurl are mutually exclusive")
|
"neutrino.feeurl are mutually exclusive")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,7 +363,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
// this back to the btcwallet/bitcoind port.
|
// this back to the btcwallet/bitcoind port.
|
||||||
rpcPort, err := strconv.Atoi(cfg.ActiveNetParams.RPCPort)
|
rpcPort, err := strconv.Atoi(cfg.ActiveNetParams.RPCPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
rpcPort -= 2
|
rpcPort -= 2
|
||||||
bitcoindHost = fmt.Sprintf("%v:%d",
|
bitcoindHost = fmt.Sprintf("%v:%d",
|
||||||
@ -400,11 +400,11 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
PrunedModeMaxPeers: bitcoindMode.PrunedNodeMaxPeers,
|
PrunedModeMaxPeers: bitcoindMode.PrunedNodeMaxPeers,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bitcoindConn.Start(); err != nil {
|
if err := bitcoindConn.Start(); err != nil {
|
||||||
return nil, fmt.Errorf("unable to connect to bitcoind: "+
|
return nil, nil, fmt.Errorf("unable to connect to bitcoind: "+
|
||||||
"%v", err)
|
"%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +439,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
fallBackFeeRate.FeePerKWeight(),
|
fallBackFeeRate.FeePerKWeight(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else if cfg.Litecoin.Active && !cfg.Litecoin.RegTest {
|
} else if cfg.Litecoin.Active && !cfg.Litecoin.RegTest {
|
||||||
log.Infof("Initializing litecoind backed fee estimator in "+
|
log.Infof("Initializing litecoind backed fee estimator in "+
|
||||||
@ -455,7 +455,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
fallBackFeeRate.FeePerKWeight(),
|
fallBackFeeRate.FeePerKWeight(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,14 +464,14 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
// connection.
|
// connection.
|
||||||
chainConn, err := rpcclient.New(rpcConfig, nil)
|
chainConn, err := rpcclient.New(rpcConfig, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The api we will use for our health check depends on the
|
// The api we will use for our health check depends on the
|
||||||
// bitcoind version.
|
// bitcoind version.
|
||||||
cmd, err := getBitcoindHealthCheckCmd(chainConn)
|
cmd, err := getBitcoindHealthCheckCmd(chainConn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cc.HealthCheck = func() error {
|
cc.HealthCheck = func() error {
|
||||||
@ -497,19 +497,19 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
if btcdMode.RawRPCCert != "" {
|
if btcdMode.RawRPCCert != "" {
|
||||||
rpcCert, err = hex.DecodeString(btcdMode.RawRPCCert)
|
rpcCert, err = hex.DecodeString(btcdMode.RawRPCCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
certFile, err := os.Open(btcdMode.RPCCert)
|
certFile, err := os.Open(btcdMode.RPCCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
rpcCert, err = ioutil.ReadAll(certFile)
|
rpcCert, err = ioutil.ReadAll(certFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if err := certFile.Close(); err != nil {
|
if err := certFile.Close(); err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,7 +541,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
rpcConfig, cfg.ActiveNetParams.Params, hintCache, hintCache,
|
rpcConfig, cfg.ActiveNetParams.Params, hintCache, hintCache,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, we'll create an instance of the default chain view to be
|
// Finally, we'll create an instance of the default chain view to be
|
||||||
@ -549,7 +549,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
cc.ChainView, err = chainview.NewBtcdFilteredChainView(*rpcConfig)
|
cc.ChainView, err = chainview.NewBtcdFilteredChainView(*rpcConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("unable to create chain view: %v", err)
|
log.Errorf("unable to create chain view: %v", err)
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a special websockets rpc client for btcd which will be used
|
// Create a special websockets rpc client for btcd which will be used
|
||||||
@ -557,7 +557,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
chainRPC, err := chain.NewRPCClient(cfg.ActiveNetParams.Params, btcdHost,
|
chainRPC, err := chain.NewRPCClient(cfg.ActiveNetParams.Params, btcdHost,
|
||||||
btcdUser, btcdPass, rpcCert, false, 20)
|
btcdUser, btcdPass, rpcCert, false, 20)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
walletConfig.ChainSource = chainRPC
|
walletConfig.ChainSource = chainRPC
|
||||||
@ -584,11 +584,11 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
*rpcConfig, fallBackFeeRate.FeePerKWeight(),
|
*rpcConfig, fallBackFeeRate.FeePerKWeight(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown node type: %s",
|
return nil, nil, fmt.Errorf("unknown node type: %s",
|
||||||
homeChainConfig.Node)
|
homeChainConfig.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,7 +599,7 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
case cfg.FeeURL == "" && cfg.Bitcoin.MainNet &&
|
case cfg.FeeURL == "" && cfg.Bitcoin.MainNet &&
|
||||||
homeChainConfig.Node == "neutrino":
|
homeChainConfig.Node == "neutrino":
|
||||||
|
|
||||||
return nil, fmt.Errorf("--feeurl parameter required when " +
|
return nil, nil, fmt.Errorf("--feeurl parameter required when " +
|
||||||
"running neutrino on mainnet")
|
"running neutrino on mainnet")
|
||||||
|
|
||||||
// Override default fee estimator if an external service is specified.
|
// Override default fee estimator if an external service is specified.
|
||||||
@ -619,15 +619,29 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ccCleanup := func() {
|
||||||
|
if cc.Wallet != nil {
|
||||||
|
if err := cc.Wallet.Shutdown(); err != nil {
|
||||||
|
log.Errorf("Failed to shutdown wallet: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc.FeeEstimator != nil {
|
||||||
|
if err := cc.FeeEstimator.Stop(); err != nil {
|
||||||
|
log.Errorf("Failed to stop feeEstimator: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start fee estimator.
|
// Start fee estimator.
|
||||||
if err := cc.FeeEstimator.Start(); err != nil {
|
if err := cc.FeeEstimator.Start(); err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
wc, err := btcwallet.New(*walletConfig)
|
wc, err := btcwallet.New(*walletConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unable to create wallet controller: %v\n", err)
|
fmt.Printf("unable to create wallet controller: %v\n", err)
|
||||||
return nil, err
|
return nil, ccCleanup, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cc.MsgSigner = wc
|
cc.MsgSigner = wc
|
||||||
@ -662,18 +676,17 @@ func NewChainControl(cfg *Config) (*ChainControl, error) {
|
|||||||
lnWallet, err := lnwallet.NewLightningWallet(walletCfg)
|
lnWallet, err := lnwallet.NewLightningWallet(walletCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unable to create wallet: %v\n", err)
|
fmt.Printf("unable to create wallet: %v\n", err)
|
||||||
return nil, err
|
return nil, ccCleanup, err
|
||||||
}
|
}
|
||||||
if err := lnWallet.Startup(); err != nil {
|
if err := lnWallet.Startup(); err != nil {
|
||||||
fmt.Printf("unable to start wallet: %v\n", err)
|
fmt.Printf("unable to start wallet: %v\n", err)
|
||||||
return nil, err
|
return nil, ccCleanup, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("LightningWallet opened")
|
log.Info("LightningWallet opened")
|
||||||
|
|
||||||
cc.Wallet = lnWallet
|
cc.Wallet = lnWallet
|
||||||
|
|
||||||
return cc, nil
|
return cc, ccCleanup, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getBitcoindHealthCheckCmd queries bitcoind for its version to decide which
|
// getBitcoindHealthCheckCmd queries bitcoind for its version to decide which
|
||||||
|
@ -86,10 +86,12 @@ func (c *ChannelNotifier) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop signals the notifier for a graceful shutdown.
|
// Stop signals the notifier for a graceful shutdown.
|
||||||
func (c *ChannelNotifier) Stop() {
|
func (c *ChannelNotifier) Stop() error {
|
||||||
|
var err error
|
||||||
c.stopped.Do(func() {
|
c.stopped.Do(func() {
|
||||||
c.ntfnServer.Stop()
|
err = c.ntfnServer.Stop()
|
||||||
})
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeChannelEvents returns a subscribe.Client that will receive updates
|
// SubscribeChannelEvents returns a subscribe.Client that will receive updates
|
||||||
|
@ -465,8 +465,9 @@ func (d *AuthenticatedGossiper) start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop signals any active goroutines for a graceful closure.
|
// Stop signals any active goroutines for a graceful closure.
|
||||||
func (d *AuthenticatedGossiper) Stop() {
|
func (d *AuthenticatedGossiper) Stop() error {
|
||||||
d.stopped.Do(d.stop)
|
d.stopped.Do(d.stop)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *AuthenticatedGossiper) stop() {
|
func (d *AuthenticatedGossiper) stop() {
|
||||||
|
@ -675,12 +675,14 @@ func (f *Manager) start() error {
|
|||||||
|
|
||||||
// Stop signals all helper goroutines to execute a graceful shutdown. This
|
// Stop signals all helper goroutines to execute a graceful shutdown. This
|
||||||
// method will block until all goroutines have exited.
|
// method will block until all goroutines have exited.
|
||||||
func (f *Manager) Stop() {
|
func (f *Manager) Stop() error {
|
||||||
f.stopped.Do(func() {
|
f.stopped.Do(func() {
|
||||||
log.Info("Funding manager shutting down")
|
log.Info("Funding manager shutting down")
|
||||||
close(f.quit)
|
close(f.quit)
|
||||||
f.wg.Wait()
|
f.wg.Wait()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextPendingChanID returns the next free pending channel ID to be used to
|
// nextPendingChanID returns the next free pending channel ID to be used to
|
||||||
|
@ -484,7 +484,9 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
|
|||||||
func recreateAliceFundingManager(t *testing.T, alice *testNode) {
|
func recreateAliceFundingManager(t *testing.T, alice *testNode) {
|
||||||
// Stop the old fundingManager before creating a new one.
|
// Stop the old fundingManager before creating a new one.
|
||||||
close(alice.shutdownChannel)
|
close(alice.shutdownChannel)
|
||||||
alice.fundingMgr.Stop()
|
if err := alice.fundingMgr.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed stop funding manager: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
aliceMsgChan := make(chan lnwire.Message)
|
aliceMsgChan := make(chan lnwire.Message)
|
||||||
aliceAnnounceChan := make(chan lnwire.Message)
|
aliceAnnounceChan := make(chan lnwire.Message)
|
||||||
@ -622,8 +624,12 @@ func tearDownFundingManagers(t *testing.T, a, b *testNode) {
|
|||||||
close(a.shutdownChannel)
|
close(a.shutdownChannel)
|
||||||
close(b.shutdownChannel)
|
close(b.shutdownChannel)
|
||||||
|
|
||||||
a.fundingMgr.Stop()
|
if err := a.fundingMgr.Stop(); err != nil {
|
||||||
b.fundingMgr.Stop()
|
t.Fatalf("failed stop funding manager: %v", err)
|
||||||
|
}
|
||||||
|
if err := b.fundingMgr.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed stop funding manager: %v", err)
|
||||||
|
}
|
||||||
os.RemoveAll(a.testDir)
|
os.RemoveAll(a.testDir)
|
||||||
os.RemoveAll(b.testDir)
|
os.RemoveAll(b.testDir)
|
||||||
}
|
}
|
||||||
@ -1502,7 +1508,9 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
|
|||||||
// implementation, and expect it to retry sending the fundingLocked
|
// implementation, and expect it to retry sending the fundingLocked
|
||||||
// message. We'll explicitly shut down Alice's funding manager to
|
// message. We'll explicitly shut down Alice's funding manager to
|
||||||
// prevent a race when overriding the sendMessage implementation.
|
// prevent a race when overriding the sendMessage implementation.
|
||||||
alice.fundingMgr.Stop()
|
if err := alice.fundingMgr.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed stop funding manager: %v", err)
|
||||||
|
}
|
||||||
bob.sendMessage = workingSendMessage
|
bob.sendMessage = workingSendMessage
|
||||||
recreateAliceFundingManager(t, alice)
|
recreateAliceFundingManager(t, alice)
|
||||||
|
|
||||||
|
@ -87,12 +87,14 @@ func (h *HtlcNotifier) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop signals the notifier for a graceful shutdown.
|
// Stop signals the notifier for a graceful shutdown.
|
||||||
func (h *HtlcNotifier) Stop() {
|
func (h *HtlcNotifier) Stop() error {
|
||||||
|
var err error
|
||||||
h.stopped.Do(func() {
|
h.stopped.Do(func() {
|
||||||
if err := h.ntfnServer.Stop(); err != nil {
|
if err = h.ntfnServer.Stop(); err != nil {
|
||||||
log.Warnf("error stopping htlc notifier: %v", err)
|
log.Warnf("error stopping htlc notifier: %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribeHtlcEvents returns a subscribe.Client that will receive updates
|
// SubscribeHtlcEvents returns a subscribe.Client that will receive updates
|
||||||
|
@ -2867,19 +2867,31 @@ func testHtcNotifier(t *testing.T, testOpts []serverOption, iterations int,
|
|||||||
if err := aliceNotifier.Start(); err != nil {
|
if err := aliceNotifier.Start(); err != nil {
|
||||||
t.Fatalf("could not start alice notifier")
|
t.Fatalf("could not start alice notifier")
|
||||||
}
|
}
|
||||||
defer aliceNotifier.Stop()
|
defer func() {
|
||||||
|
if err := aliceNotifier.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed to stop alice notifier: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
bobNotifier := NewHtlcNotifier(mockTime)
|
bobNotifier := NewHtlcNotifier(mockTime)
|
||||||
if err := bobNotifier.Start(); err != nil {
|
if err := bobNotifier.Start(); err != nil {
|
||||||
t.Fatalf("could not start bob notifier")
|
t.Fatalf("could not start bob notifier")
|
||||||
}
|
}
|
||||||
defer bobNotifier.Stop()
|
defer func() {
|
||||||
|
if err := bobNotifier.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed to stop bob notifier: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
carolNotifier := NewHtlcNotifier(mockTime)
|
carolNotifier := NewHtlcNotifier(mockTime)
|
||||||
if err := carolNotifier.Start(); err != nil {
|
if err := carolNotifier.Start(); err != nil {
|
||||||
t.Fatalf("could not start carol notifier")
|
t.Fatalf("could not start carol notifier")
|
||||||
}
|
}
|
||||||
defer carolNotifier.Stop()
|
defer func() {
|
||||||
|
if err := carolNotifier.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed to stop carol notifier: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Create a notifier server option which will set our htlc notifiers
|
// Create a notifier server option which will set our htlc notifiers
|
||||||
// for the three hop network.
|
// for the three hop network.
|
||||||
|
@ -237,7 +237,7 @@ func (i *InvoiceRegistry) Start() error {
|
|||||||
// delete them.
|
// delete them.
|
||||||
err = i.scanInvoicesOnStart()
|
err = i.scanInvoicesOnStart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.Stop()
|
_ = i.Stop()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,12 +245,13 @@ func (i *InvoiceRegistry) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop signals the registry for a graceful shutdown.
|
// Stop signals the registry for a graceful shutdown.
|
||||||
func (i *InvoiceRegistry) Stop() {
|
func (i *InvoiceRegistry) Stop() error {
|
||||||
i.expiryWatcher.Stop()
|
i.expiryWatcher.Stop()
|
||||||
|
|
||||||
close(i.quit)
|
close(i.quit)
|
||||||
|
|
||||||
i.wg.Wait()
|
i.wg.Wait()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// invoiceEvent represents a new event that has modified on invoice on disk.
|
// invoiceEvent represents a new event that has modified on invoice on disk.
|
||||||
|
@ -527,7 +527,11 @@ func TestCancelHoldInvoice(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer registry.Stop()
|
defer func() {
|
||||||
|
if err := registry.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed to stop invoice registry: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Add the invoice.
|
// Add the invoice.
|
||||||
_, err = registry.AddInvoice(testHodlInvoice, testInvoicePaymentHash)
|
_, err = registry.AddInvoice(testHodlInvoice, testInvoicePaymentHash)
|
||||||
@ -1005,7 +1009,9 @@ func TestInvoiceExpiryWithRegistry(t *testing.T) {
|
|||||||
|
|
||||||
// Give some time to the watcher to cancel everything.
|
// Give some time to the watcher to cancel everything.
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
registry.Stop()
|
if err = registry.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed to stop invoice registry: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Create the expected cancellation set before the final check.
|
// Create the expected cancellation set before the final check.
|
||||||
expectedCancellations = append(
|
expectedCancellations = append(
|
||||||
|
@ -215,7 +215,9 @@ func newTestContext(t *testing.T) *testContext {
|
|||||||
clock: clock,
|
clock: clock,
|
||||||
t: t,
|
t: t,
|
||||||
cleanup: func() {
|
cleanup: func() {
|
||||||
registry.Stop()
|
if err = registry.Stop(); err != nil {
|
||||||
|
t.Fatalf("failed to stop invoice registry: %v", err)
|
||||||
|
}
|
||||||
cleanup()
|
cleanup()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
5
lnd.go
5
lnd.go
@ -548,7 +548,10 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
activeChainControl, err := chainreg.NewChainControl(chainControlCfg)
|
activeChainControl, cleanup, err := chainreg.NewChainControl(chainControlCfg)
|
||||||
|
if cleanup != nil {
|
||||||
|
defer cleanup()
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("unable to create chain control: %v", err)
|
err := fmt.Errorf("unable to create chain control: %v", err)
|
||||||
ltndLog.Error(err)
|
ltndLog.Error(err)
|
||||||
|
@ -49,11 +49,13 @@ func (p *PeerNotifier) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop signals the notifier for a graceful shutdown.
|
// Stop signals the notifier for a graceful shutdown.
|
||||||
func (p *PeerNotifier) Stop() {
|
func (p *PeerNotifier) Stop() error {
|
||||||
|
var err error
|
||||||
p.stopped.Do(func() {
|
p.stopped.Do(func() {
|
||||||
log.Info("Stopping PeerNotifier")
|
log.Info("Stopping PeerNotifier")
|
||||||
p.ntfnServer.Stop()
|
err = p.ntfnServer.Stop()
|
||||||
})
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscribePeerEvents returns a subscribe.Client that will receive updates
|
// SubscribePeerEvents returns a subscribe.Client that will receive updates
|
||||||
|
140
server.go
140
server.go
@ -1435,17 +1435,45 @@ func (s *server) Started() bool {
|
|||||||
return atomic.LoadInt32(&s.active) != 0
|
return atomic.LoadInt32(&s.active) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cleaner is used to aggregate "cleanup" functions during an operation that
|
||||||
|
// starts several subsystems. In case one of the subsystem fails to start
|
||||||
|
// and a proper resource cleanup is required, the "run" method achieves this
|
||||||
|
// by running all these added "cleanup" functions
|
||||||
|
type cleaner []func() error
|
||||||
|
|
||||||
|
// add is used to add a cleanup function to be called when
|
||||||
|
// the run function is executed
|
||||||
|
func (c cleaner) add(cleanup func() error) cleaner {
|
||||||
|
return append(c, cleanup)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run is used to run all the previousely added cleanup functions
|
||||||
|
func (c cleaner) run() {
|
||||||
|
for i := len(c) - 1; i >= 0; i-- {
|
||||||
|
if err := c[i](); err != nil {
|
||||||
|
srvrLog.Infof("Cleanup failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start starts the main daemon server, all requested listeners, and any helper
|
// Start starts the main daemon server, all requested listeners, and any helper
|
||||||
// goroutines.
|
// goroutines.
|
||||||
// NOTE: This function is safe for concurrent access.
|
// NOTE: This function is safe for concurrent access.
|
||||||
func (s *server) Start() error {
|
func (s *server) Start() error {
|
||||||
var startErr error
|
var startErr error
|
||||||
|
|
||||||
|
// If one sub system fails to start, the following code ensures that the
|
||||||
|
// previous started ones are stopped. It also ensures a proper wallet
|
||||||
|
// shutdown which is important for releasing its resources (boltdb, etc...)
|
||||||
|
cleanup := cleaner{}
|
||||||
|
|
||||||
s.start.Do(func() {
|
s.start.Do(func() {
|
||||||
if s.torController != nil {
|
if s.torController != nil {
|
||||||
if err := s.createNewHiddenService(); err != nil {
|
if err := s.createNewHiddenService(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.torController.Stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.natTraversal != nil {
|
if s.natTraversal != nil {
|
||||||
@ -1458,6 +1486,7 @@ func (s *server) Start() error {
|
|||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.hostAnn.Stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.livelinessMonitor != nil {
|
if s.livelinessMonitor != nil {
|
||||||
@ -1465,6 +1494,7 @@ func (s *server) Start() error {
|
|||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.livelinessMonitor.Stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the notification server. This is used so channel
|
// Start the notification server. This is used so channel
|
||||||
@ -1476,91 +1506,134 @@ func (s *server) Start() error {
|
|||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.sigPool.Stop)
|
||||||
|
|
||||||
if err := s.writePool.Start(); err != nil {
|
if err := s.writePool.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.writePool.Stop)
|
||||||
|
|
||||||
if err := s.readPool.Start(); err != nil {
|
if err := s.readPool.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.readPool.Stop)
|
||||||
|
|
||||||
if err := s.cc.ChainNotifier.Start(); err != nil {
|
if err := s.cc.ChainNotifier.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.cc.ChainNotifier.Stop)
|
||||||
|
|
||||||
if err := s.channelNotifier.Start(); err != nil {
|
if err := s.channelNotifier.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.channelNotifier.Stop)
|
||||||
|
|
||||||
if err := s.peerNotifier.Start(); err != nil {
|
if err := s.peerNotifier.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(func() error {
|
||||||
|
return s.peerNotifier.Stop()
|
||||||
|
})
|
||||||
if err := s.htlcNotifier.Start(); err != nil {
|
if err := s.htlcNotifier.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.htlcNotifier.Stop)
|
||||||
|
|
||||||
if err := s.sphinx.Start(); err != nil {
|
if err := s.sphinx.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.sphinx.Stop)
|
||||||
|
|
||||||
if s.towerClient != nil {
|
if s.towerClient != nil {
|
||||||
if err := s.towerClient.Start(); err != nil {
|
if err := s.towerClient.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.towerClient.Stop)
|
||||||
}
|
}
|
||||||
if s.anchorTowerClient != nil {
|
if s.anchorTowerClient != nil {
|
||||||
if err := s.anchorTowerClient.Start(); err != nil {
|
if err := s.anchorTowerClient.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.anchorTowerClient.Stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.htlcSwitch.Start(); err != nil {
|
if err := s.htlcSwitch.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.htlcSwitch.Stop)
|
||||||
|
|
||||||
if err := s.sweeper.Start(); err != nil {
|
if err := s.sweeper.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.sweeper.Stop)
|
||||||
|
|
||||||
if err := s.utxoNursery.Start(); err != nil {
|
if err := s.utxoNursery.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.utxoNursery.Stop)
|
||||||
|
|
||||||
if err := s.chainArb.Start(); err != nil {
|
if err := s.chainArb.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.chainArb.Stop)
|
||||||
|
|
||||||
if err := s.breachArbiter.Start(); err != nil {
|
if err := s.breachArbiter.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.breachArbiter.Stop)
|
||||||
|
|
||||||
if err := s.authGossiper.Start(); err != nil {
|
if err := s.authGossiper.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.authGossiper.Stop)
|
||||||
|
|
||||||
if err := s.chanRouter.Start(); err != nil {
|
if err := s.chanRouter.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.chanRouter.Stop)
|
||||||
|
|
||||||
if err := s.fundingMgr.Start(); err != nil {
|
if err := s.fundingMgr.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.fundingMgr.Stop)
|
||||||
|
|
||||||
if err := s.invoices.Start(); err != nil {
|
if err := s.invoices.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.invoices.Stop)
|
||||||
|
|
||||||
if err := s.chanStatusMgr.Start(); err != nil {
|
if err := s.chanStatusMgr.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.chanStatusMgr.Stop)
|
||||||
|
|
||||||
if err := s.chanEventStore.Start(); err != nil {
|
if err := s.chanEventStore.Start(); err != nil {
|
||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(func() error {
|
||||||
|
s.chanEventStore.Stop()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
// Before we start the connMgr, we'll check to see if we have
|
// Before we start the connMgr, we'll check to see if we have
|
||||||
// any backups to recover. We do this now as we want to ensure
|
// any backups to recover. We do this now as we want to ensure
|
||||||
@ -1598,8 +1671,13 @@ func (s *server) Start() error {
|
|||||||
startErr = err
|
startErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cleanup = cleanup.add(s.chanSubSwapper.Stop)
|
||||||
|
|
||||||
s.connMgr.Start()
|
s.connMgr.Start()
|
||||||
|
cleanup = cleanup.add(func() error {
|
||||||
|
s.connMgr.Stop()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
// With all the relevant sub-systems started, we'll now attempt
|
// With all the relevant sub-systems started, we'll now attempt
|
||||||
// to establish persistent connections to our direct channel
|
// to establish persistent connections to our direct channel
|
||||||
@ -1692,6 +1770,9 @@ func (s *server) Start() error {
|
|||||||
atomic.StoreInt32(&s.active, 1)
|
atomic.StoreInt32(&s.active, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if startErr != nil {
|
||||||
|
cleanup.run()
|
||||||
|
}
|
||||||
return startErr
|
return startErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1710,30 +1791,49 @@ func (s *server) Stop() error {
|
|||||||
if err := s.cc.ChainNotifier.Stop(); err != nil {
|
if err := s.cc.ChainNotifier.Stop(); err != nil {
|
||||||
srvrLog.Warnf("Unable to stop ChainNotifier: %v", err)
|
srvrLog.Warnf("Unable to stop ChainNotifier: %v", err)
|
||||||
}
|
}
|
||||||
s.chanRouter.Stop()
|
if err := s.chanRouter.Stop(); err != nil {
|
||||||
s.htlcSwitch.Stop()
|
srvrLog.Warnf("failed to stop chanRouter: %v", err)
|
||||||
s.sphinx.Stop()
|
|
||||||
s.utxoNursery.Stop()
|
|
||||||
s.breachArbiter.Stop()
|
|
||||||
s.authGossiper.Stop()
|
|
||||||
s.chainArb.Stop()
|
|
||||||
s.sweeper.Stop()
|
|
||||||
s.channelNotifier.Stop()
|
|
||||||
s.peerNotifier.Stop()
|
|
||||||
s.htlcNotifier.Stop()
|
|
||||||
if err := s.cc.Wallet.Shutdown(); err != nil {
|
|
||||||
srvrLog.Warnf("Unable to stop Wallet: %v", err)
|
|
||||||
}
|
}
|
||||||
if err := s.cc.ChainView.Stop(); err != nil {
|
if err := s.htlcSwitch.Stop(); err != nil {
|
||||||
srvrLog.Warnf("Unable to stop ChainView: %v", err)
|
srvrLog.Warnf("failed to stop htlcSwitch: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.sphinx.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop sphinx: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.utxoNursery.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop utxoNursery: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.breachArbiter.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop breachArbiter: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.authGossiper.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop authGossiper: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.chainArb.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop chainArb: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.sweeper.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop sweeper: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.channelNotifier.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop channelNotifier: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.peerNotifier.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop peerNotifier: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.htlcNotifier.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop htlcNotifier: %v", err)
|
||||||
}
|
}
|
||||||
s.connMgr.Stop()
|
s.connMgr.Stop()
|
||||||
if err := s.cc.FeeEstimator.Stop(); err != nil {
|
if err := s.invoices.Stop(); err != nil {
|
||||||
srvrLog.Warnf("Unable to stop FeeEstimator: %v", err)
|
srvrLog.Warnf("failed to stop invoices: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.fundingMgr.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop fundingMgr: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.chanSubSwapper.Stop(); err != nil {
|
||||||
|
srvrLog.Warnf("failed to stop chanSubSwapper: %v", err)
|
||||||
}
|
}
|
||||||
s.invoices.Stop()
|
|
||||||
s.fundingMgr.Stop()
|
|
||||||
s.chanSubSwapper.Stop()
|
|
||||||
s.chanEventStore.Stop()
|
s.chanEventStore.Stop()
|
||||||
|
|
||||||
// Disconnect from each active peers to ensure that
|
// Disconnect from each active peers to ensure that
|
||||||
|
Loading…
Reference in New Issue
Block a user