@@ -4,13 +4,18 @@ import (
4
4
"context"
5
5
"fmt"
6
6
"strconv"
7
+ "sync"
8
+ "time"
7
9
8
10
"github.com/btcsuite/btcd/btcutil"
9
11
"github.com/lightninglabs/lndclient"
10
12
"github.com/lightningnetwork/lnd/routing/route"
11
13
"github.com/prometheus/client_golang/prometheus"
12
14
)
13
15
16
+ // Cache refresh interval magic number.
17
+ const cacheRefreshInterval = 10 * time .Minute
18
+
14
19
// ChannelsCollector is a collector that keeps track of channel information.
15
20
type ChannelsCollector struct {
16
21
channelBalanceDesc * prometheus.Desc
@@ -51,17 +56,25 @@ type ChannelsCollector struct {
51
56
// errChan is a channel that we send any errors that we encounter into.
52
57
// This channel should be buffered so that it does not block sends.
53
58
errChan chan <- error
59
+
60
+ // quit is a channel that we use to signal for graceful shutdown.
61
+ quit chan struct {}
62
+
63
+ // cache is for storing results from a ticker to reduce grpc server
64
+ // load on lnd.
65
+ closedChannelsCache []lndclient.ClosedChannel
66
+ cacheMutex sync.RWMutex
54
67
}
55
68
56
69
// NewChannelsCollector returns a new instance of the ChannelsCollector for the
57
70
// target lnd client.
58
71
func NewChannelsCollector (lnd lndclient.LightningClient , errChan chan <- error ,
59
- cfg * MonitoringConfig ) * ChannelsCollector {
72
+ quitChan chan struct {}, cfg * MonitoringConfig ) * ChannelsCollector {
60
73
61
74
// Our set of labels, status should either be active or inactive. The
62
75
// initiator is "true" if we are the initiator, and "false" otherwise.
63
76
labels := []string {"chan_id" , "status" , "initiator" , "peer" }
64
- return & ChannelsCollector {
77
+ collector := & ChannelsCollector {
65
78
channelBalanceDesc : prometheus .NewDesc (
66
79
"lnd_channels_open_balance_sat" ,
67
80
"total balance of channels in satoshis" ,
@@ -174,10 +187,49 @@ func NewChannelsCollector(lnd lndclient.LightningClient, errChan chan<- error,
174
187
[]string {"amount" }, nil ,
175
188
),
176
189
177
- lnd : lnd ,
178
- primaryNode : cfg .PrimaryNode ,
179
- errChan : errChan ,
190
+ lnd : lnd ,
191
+ primaryNode : cfg .PrimaryNode ,
192
+ closedChannelsCache : nil ,
193
+ errChan : errChan ,
194
+ quit : quitChan ,
180
195
}
196
+
197
+ // Start a ticker to update the cache once per 10m
198
+ go func () {
199
+ ticker := time .NewTicker (cacheRefreshInterval )
200
+ defer ticker .Stop ()
201
+
202
+ for {
203
+ err := collector .refreshClosedChannelsCache ()
204
+ if err != nil {
205
+ errChan <- err
206
+ }
207
+
208
+ select {
209
+ case <- ticker .C :
210
+ continue
211
+
212
+ case <- collector .quit :
213
+ return
214
+ }
215
+ }
216
+ }()
217
+
218
+ return collector
219
+ }
220
+
221
+ // refreshClosedChannelsCache acquires a mutex write lock to update
222
+ // the closedChannelsCache.
223
+ func (c * ChannelsCollector ) refreshClosedChannelsCache () error {
224
+ data , err := c .lnd .ClosedChannels (context .Background ())
225
+ if err != nil {
226
+ return err
227
+ }
228
+ c .cacheMutex .Lock ()
229
+ c .closedChannelsCache = data
230
+ c .cacheMutex .Unlock ()
231
+
232
+ return nil
181
233
}
182
234
183
235
// Describe sends the super-set of all possible descriptors of metrics
@@ -452,12 +504,9 @@ func (c *ChannelsCollector) Collect(ch chan<- prometheus.Metric) {
452
504
)
453
505
454
506
// Get the list of closed channels.
455
- closedChannelsResp , err := c .lnd .ClosedChannels (context .Background ())
456
- if err != nil {
457
- c .errChan <- fmt .Errorf ("ChannelsCollector ClosedChannels " +
458
- "failed with: %v" , err )
459
- return
460
- }
507
+ c .cacheMutex .RLock ()
508
+ closedChannelsResp := c .closedChannelsCache
509
+ c .cacheMutex .RUnlock ()
461
510
closeCounts := make (map [string ]int )
462
511
for _ , channel := range closedChannelsResp {
463
512
typeString , ok := closeTypeLabelMap [channel .CloseType ]
0 commit comments