@@ -4,13 +4,18 @@ import (
44 "context"
55 "fmt"
66 "strconv"
7+ "sync"
8+ "time"
79
810 "github.com/btcsuite/btcd/btcutil"
911 "github.com/lightninglabs/lndclient"
1012 "github.com/lightningnetwork/lnd/routing/route"
1113 "github.com/prometheus/client_golang/prometheus"
1214)
1315
16+ // Cache refresh interval magic number.
17+ const cacheRefreshInterval = 10 * time .Minute
18+
1419// ChannelsCollector is a collector that keeps track of channel information.
1520type ChannelsCollector struct {
1621 channelBalanceDesc * prometheus.Desc
@@ -51,17 +56,25 @@ type ChannelsCollector struct {
5156 // errChan is a channel that we send any errors that we encounter into.
5257 // This channel should be buffered so that it does not block sends.
5358 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
5467}
5568
5669// NewChannelsCollector returns a new instance of the ChannelsCollector for the
5770// target lnd client.
5871func NewChannelsCollector (lnd lndclient.LightningClient , errChan chan <- error ,
59- cfg * MonitoringConfig ) * ChannelsCollector {
72+ quitChan chan struct {}, cfg * MonitoringConfig ) * ChannelsCollector {
6073
6174 // Our set of labels, status should either be active or inactive. The
6275 // initiator is "true" if we are the initiator, and "false" otherwise.
6376 labels := []string {"chan_id" , "status" , "initiator" , "peer" }
64- return & ChannelsCollector {
77+ collector := & ChannelsCollector {
6578 channelBalanceDesc : prometheus .NewDesc (
6679 "lnd_channels_open_balance_sat" ,
6780 "total balance of channels in satoshis" ,
@@ -174,10 +187,49 @@ func NewChannelsCollector(lnd lndclient.LightningClient, errChan chan<- error,
174187 []string {"amount" }, nil ,
175188 ),
176189
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 ,
180195 }
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
181233}
182234
183235// Describe sends the super-set of all possible descriptors of metrics
@@ -452,12 +504,9 @@ func (c *ChannelsCollector) Collect(ch chan<- prometheus.Metric) {
452504 )
453505
454506 // 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 ()
461510 closeCounts := make (map [string ]int )
462511 for _ , channel := range closedChannelsResp {
463512 typeString , ok := closeTypeLabelMap [channel .CloseType ]
0 commit comments