Skip to content

Commit 16be260

Browse files
committed
lit: make sure to always close stores on errored start-up
Ensure that if any store init in the `stores` struct creation fails, then any successful stores are still closed during shutdown.
1 parent ee0d8e4 commit 16be260

File tree

3 files changed

+71
-73
lines changed

3 files changed

+71
-73
lines changed

config_dev.go

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ func NewStores(cfg *Config, clock clock.Clock) (*stores, error) {
8989
networkDir = filepath.Join(cfg.LitDir, cfg.Network)
9090
acctStore accounts.Store
9191
sessStore session.Store
92-
closeFns = make(map[string]func() error)
92+
93+
stores = &stores{
94+
closeFns: make(map[string]func() error),
95+
}
9396
)
9497

9598
switch cfg.DatabaseBackend {
@@ -98,76 +101,68 @@ func NewStores(cfg *Config, clock clock.Clock) (*stores, error) {
98101
// the directory where we will store the database file exists.
99102
err := makeDirectories(networkDir)
100103
if err != nil {
101-
return nil, err
104+
return stores, err
102105
}
103106

104107
sqlStore, err := db.NewSqliteStore(cfg.Sqlite)
105108
if err != nil {
106-
return nil, err
109+
return stores, err
107110
}
108111

109112
acctStore = accounts.NewSQLStore(sqlStore.BaseDB, clock)
110113
sessStore = session.NewSQLStore(sqlStore.BaseDB, clock)
111-
closeFns["sqlite"] = sqlStore.BaseDB.Close
114+
115+
stores.accounts = acctStore
116+
stores.sessions = sessStore
117+
stores.closeFns["sqlite"] = sqlStore.BaseDB.Close
112118

113119
case DatabaseBackendPostgres:
114120
sqlStore, err := db.NewPostgresStore(cfg.Postgres)
115121
if err != nil {
116-
return nil, err
122+
return stores, err
117123
}
118124

119125
acctStore = accounts.NewSQLStore(sqlStore.BaseDB, clock)
120126
sessStore = session.NewSQLStore(sqlStore.BaseDB, clock)
121-
closeFns["postgres"] = sqlStore.BaseDB.Close
127+
128+
stores.accounts = acctStore
129+
stores.sessions = sessStore
130+
stores.closeFns["postgres"] = sqlStore.BaseDB.Close
122131

123132
default:
124133
accountStore, err := accounts.NewBoltStore(
125134
filepath.Dir(cfg.MacaroonPath), accounts.DBFilename,
126135
clock,
127136
)
128137
if err != nil {
129-
return nil, err
138+
return stores, err
130139
}
131-
closeFns["bbolt-accounts"] = accountStore.Close
140+
141+
stores.accounts = accountStore
142+
stores.closeFns["bbolt-accounts"] = accountStore.Close
132143

133144
sessionStore, err := session.NewDB(
134145
networkDir, session.DBFilename, clock, accountStore,
135146
)
136147
if err != nil {
137-
return nil, err
148+
return stores, err
138149
}
139-
closeFns["bbolt-sessions"] = sessionStore.Close
140150

141-
acctStore = accountStore
142-
sessStore = sessionStore
151+
stores.sessions = sessionStore
152+
stores.closeFns["bbolt-sessions"] = sessionStore.Close
143153
}
144154

145155
firewallBoltDB, err := firewalldb.NewBoltDB(
146156
networkDir, firewalldb.DBFilename, sessStore,
147157
)
148158
if err != nil {
149-
return nil, fmt.Errorf("error creating firewall BoltDB: %v",
159+
return stores, fmt.Errorf("error creating firewall BoltDB: %v",
150160
err)
151161
}
152-
closeFns["bbolt-firewalldb"] = firewallBoltDB.Close
153-
154-
return &stores{
155-
accounts: acctStore,
156-
sessions: sessStore,
157-
firewall: firewalldb.NewDB(firewallBoltDB),
158-
firewallBolt: firewallBoltDB,
159-
close: func() error {
160-
var returnErr error
161-
for storeName, fn := range closeFns {
162-
err := fn()
163-
if err != nil {
164-
log.Errorf("error closing %s store: %v",
165-
storeName, err)
166-
returnErr = err
167-
}
168-
}
169-
170-
return returnErr
171-
},
172-
}, nil
162+
163+
stores.firewall = firewalldb.NewDB(firewallBoltDB)
164+
stores.firewallBolt = firewallBoltDB
165+
stores.closeFns["bbolt-firewalldb"] = firewallBoltDB.Close
166+
167+
return stores, nil
173168
}

config_prod.go

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -32,55 +32,38 @@ func (c *DevConfig) Validate(_, _ string) error {
3232
func NewStores(cfg *Config, clock clock.Clock) (*stores, error) {
3333
networkDir := filepath.Join(cfg.LitDir, cfg.Network)
3434

35+
stores := &stores{
36+
closeFns: make(map[string]func() error),
37+
}
38+
3539
acctStore, err := accounts.NewBoltStore(
3640
filepath.Dir(cfg.MacaroonPath), accounts.DBFilename, clock,
3741
)
3842
if err != nil {
39-
return nil, err
43+
return stores, err
4044
}
45+
stores.accounts = acctStore
46+
stores.closeFns["accounts"] = acctStore.Close
4147

4248
sessStore, err := session.NewDB(
4349
networkDir, session.DBFilename, clock, acctStore,
4450
)
4551
if err != nil {
46-
return nil, fmt.Errorf("error creating session BoltStore: %v",
47-
err)
52+
return stores, fmt.Errorf("error creating session BoltStore: "+
53+
"%v", err)
4854
}
55+
stores.sessions = sessStore
56+
stores.closeFns["sessions"] = sessStore.Close
4957

5058
firewallDB, err := firewalldb.NewBoltDB(
5159
networkDir, firewalldb.DBFilename, sessStore,
5260
)
5361
if err != nil {
54-
return nil, fmt.Errorf("error creating firewall DB: %v", err)
62+
return stores, fmt.Errorf("error creating firewall DB: %v", err)
5563
}
64+
stores.firewallBolt = firewallDB
65+
stores.firewall = firewalldb.NewDB(firewallDB)
66+
stores.closeFns["firewall"] = firewallDB.Close
5667

57-
return &stores{
58-
accounts: acctStore,
59-
sessions: sessStore,
60-
firewallBolt: firewallDB,
61-
firewall: firewalldb.NewDB(firewallDB),
62-
close: func() error {
63-
var returnErr error
64-
if err := acctStore.Close(); err != nil {
65-
returnErr = fmt.Errorf("error closing "+
66-
"account store: %v", err)
67-
68-
log.Error(returnErr.Error())
69-
}
70-
if err := sessStore.Close(); err != nil {
71-
returnErr = fmt.Errorf("error closing "+
72-
"session store: %v", err)
73-
74-
log.Error(returnErr.Error())
75-
}
76-
if err := firewallDB.Close(); err != nil {
77-
returnErr = fmt.Errorf("error closing "+
78-
"firewall DB: %v", err)
79-
80-
log.Error(returnErr.Error())
81-
}
82-
83-
return returnErr
84-
},
85-
}, nil
68+
return stores, nil
8669
}

terminal.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,25 @@ type stores struct {
242242
firewall *firewalldb.DB
243243
firewallBolt *firewalldb.BoltDB
244244

245-
// close is a callback that can be used to close all the stores in the
246-
// stores struct.
247-
close func() error
245+
// closeFns holds various callbacks that can be used to close any open
246+
// stores in the stores struct.
247+
closeFns map[string]func() error
248+
}
249+
250+
// close closes all open stores in the stores struct. It returns an error if
251+
// any of the stores could not be closed.
252+
func (s *stores) close() error {
253+
var returnErr error
254+
for storeName, closeFn := range s.closeFns {
255+
err := closeFn()
256+
if err != nil {
257+
log.Errorf("error closing %s store: %v",
258+
storeName, err)
259+
returnErr = err
260+
}
261+
}
262+
263+
return returnErr
248264
}
249265

250266
// Run starts everything and then blocks until either the application is shut
@@ -1450,9 +1466,13 @@ func (g *LightningTerminal) shutdownSubServers() error {
14501466
}
14511467

14521468
if g.stores != nil {
1453-
if err := g.stores.firewall.Stop(); err != nil {
1454-
log.Errorf("Error stoppint firewall DB: %v", err)
1455-
returnErr = err
1469+
if g.stores.firewall != nil {
1470+
if err := g.stores.firewall.Stop(); err != nil {
1471+
log.Errorf("Error stoppint firewall DB: %v",
1472+
err)
1473+
1474+
returnErr = err
1475+
}
14561476
}
14571477

14581478
err = g.stores.close()

0 commit comments

Comments
 (0)