github.com/status-im/status-go@v1.1.0/metrics/node/subscribe.go (about) 1 package node 2 3 import ( 4 "context" 5 "errors" 6 7 "github.com/ethereum/go-ethereum/log" 8 "github.com/ethereum/go-ethereum/node" 9 "github.com/ethereum/go-ethereum/p2p" 10 ) 11 12 // All general log messages in this package should be routed through this logger. 13 var logger = log.New("package", "status-go/metrics/node") 14 15 // SubscribeServerEvents subscribes to server and listens to 16 // PeerEventTypeAdd and PeerEventTypeDrop events. 17 func SubscribeServerEvents(ctx context.Context, node *node.Node) error { 18 server := node.Server() 19 20 if server == nil { 21 return errors.New("server is unavailable") 22 } 23 24 ch := make(chan *p2p.PeerEvent, server.MaxPeers) 25 subscription := server.SubscribeEvents(ch) 26 defer subscription.Unsubscribe() 27 28 logger.Debug("Subscribed to server events") 29 30 for { 31 select { 32 case event := <-ch: 33 if isAddDropPeerEvent(event.Type) { 34 // We start a goroutine here because updateNodeMetrics 35 // is calling a method on the p2p server, which 36 // blocks until the server is available: 37 // https://github.com/status-im/status-go/blob/e60f425b45d00d3880b42fdd77b460ec465a9f55/vendor/github.com/ethereum/go-ethereum/p2p/server.go#L301 38 // https://github.com/status-im/status-go/blob/e60f425b45d00d3880b42fdd77b460ec465a9f55/vendor/github.com/ethereum/go-ethereum/p2p/server.go#L746 39 // If there's back-pressure on the peer event feed 40 // https://github.com/status-im/status-go/blob/e60f425b45d00d3880b42fdd77b460ec465a9f55/vendor/github.com/ethereum/go-ethereum/p2p/server.go#L783 41 // The event channel above might become full while updateNodeMetrics 42 // is called, which means is never consumed, the server blocks on publishing on 43 // it, and the two will deadlock (server waits for the channel above to be consumed, 44 // this code waits for the server to respond to peerCount, which is in the same 45 // event loop). 46 // Calling it in a different go-routine will allow this code to keep 47 // processing peer added events, therefore the server will not lock and 48 // keep processing requests. 49 go func() { 50 if err := updateNodeMetrics(node, event.Type); err != nil { 51 logger.Error("failed to update node metrics", "err", err) 52 } 53 }() 54 } 55 case err := <-subscription.Err(): 56 if err != nil { 57 logger.Error("Subscription failed", "err", err) 58 } 59 return err 60 case <-ctx.Done(): 61 return nil 62 } 63 } 64 } 65 66 func isAddDropPeerEvent(eventType p2p.PeerEventType) bool { 67 return eventType == p2p.PeerEventTypeAdd || eventType == p2p.PeerEventTypeDrop 68 }