Skip to content

Commit 4750ca6

Browse files
committed
signal: ensure interceptor is closed on startup error paths
Make startup error handling consistently request and wait for interceptor shutdown so retries don’t inherit a stale interceptor instance. This is mostly relevant for the mobile bindings, where subsequent starting attempts would inherit the previous go runtime state.
1 parent 12b15c1 commit 4750ca6

3 files changed

Lines changed: 47 additions & 1 deletion

File tree

docs/release-notes/release-notes-0.21.0.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
transitions during startup, avoiding lost unlocks during slow database
7676
initialization.
7777

78+
* Ensure that the interceptor is properly closed on failure paths in `lnd.Start`
79+
7880
# New Features
7981

8082
- Basic Support for [onion messaging forwarding](https://github.com/lightningnetwork/lnd/pull/9868)
@@ -191,6 +193,7 @@
191193
* Boris Nagaev
192194
* Elle Mouton
193195
* Erick Cestari
196+
* Hampus Sjöberg
194197
* hieblmi
195198
* Matt Morehouse
196199
* Mohamed Awnallah

lnd.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ var errStreamIsolationWithProxySkip = errors.New(
146146
// This function starts all main system components then blocks until a signal
147147
// is received on the shutdownChan at which point everything is shut down again.
148148
func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
149-
interceptor signal.Interceptor) error {
149+
interceptor signal.Interceptor) (mainErr error) {
150150

151151
defer func() {
152152
ltndLog.Info("Shutdown complete")
@@ -156,6 +156,17 @@ func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
156156
}
157157
}()
158158

159+
// Make sure the signal interceptor is always fully stopped on any
160+
// startup/runtime error so callers can safely retry startup.
161+
defer func() {
162+
if mainErr == nil {
163+
return
164+
}
165+
166+
interceptor.RequestShutdown()
167+
<-interceptor.ShutdownChannel()
168+
}()
169+
159170
ctx, cancel := context.WithCancel(context.Background())
160171
defer cancel()
161172

lnd_main_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package lnd
2+
3+
import (
4+
"net"
5+
"testing"
6+
"time"
7+
8+
"github.com/lightningnetwork/lnd/lncfg"
9+
"github.com/lightningnetwork/lnd/signal"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
// TestMainErrorShutsDownInterceptor asserts that Main error paths always close
14+
// the signal interceptor so startup can be retried in-process.
15+
func TestMainErrorShutsDownInterceptor(t *testing.T) {
16+
interceptor, err := signal.Intercept()
17+
require.NoError(t, err)
18+
19+
cfg := DefaultConfig()
20+
cfg.Pprof = &lncfg.Pprof{}
21+
cfg.RPCListeners = []net.Addr{
22+
&net.UnixAddr{Net: "invalid-network"},
23+
}
24+
mainErr := Main(&cfg, ListenerCfg{}, nil, interceptor)
25+
require.Error(t, mainErr)
26+
27+
select {
28+
case <-interceptor.ShutdownChannel():
29+
case <-time.After(5 * time.Second):
30+
t.Fatalf("interceptor wasn't shut down after Main returned error")
31+
}
32+
}

0 commit comments

Comments
 (0)