99// Redistribution and use in source and binary forms with or without
1010// modifications are permitted.
1111
12+ using Akka . Actor ;
1213using Neo . Json ;
14+ using Neo . Network . P2P ;
1315using Neo . SmartContract . Native ;
1416using System . Net ;
1517using System . Text ;
@@ -27,6 +29,7 @@ public sealed class HealthCheckEndpoint : IDisposable
2729 private readonly Task _listenerTask ;
2830 private readonly string _nodeId ;
2931 private readonly string _network ;
32+ private LocalNode ? _localNode ;
3033 private bool _disposed ;
3134
3235 public HealthCheckEndpoint ( NeoSystem system , string host , int port , string nodeId , string network )
@@ -41,6 +44,8 @@ public HealthCheckEndpoint(NeoSystem system, string host, int port, string nodeI
4144 _listener . Prefixes . Add ( $ "http://{ host } :{ port } /ready/") ;
4245 _listener . Prefixes . Add ( $ "http://{ host } :{ port } /live/") ;
4346
47+ InitializeLocalNode ( ) ;
48+
4449 try
4550 {
4651 _listener . Start ( ) ;
@@ -57,6 +62,19 @@ public HealthCheckEndpoint(NeoSystem system, string host, int port, string nodeI
5762 }
5863 }
5964
65+ private async void InitializeLocalNode ( )
66+ {
67+ try
68+ {
69+ _localNode = await _system . LocalNode . Ask < LocalNode > ( new LocalNode . GetInstance ( ) ) ;
70+ }
71+ catch ( Exception ex )
72+ {
73+ Utility . Log ( nameof ( HealthCheckEndpoint ) , LogLevel . Debug ,
74+ $ "Failed to get LocalNode instance for health checks: { ex . Message } ") ;
75+ }
76+ }
77+
6078 private async Task ListenAsync ( )
6179 {
6280 while ( ! _cts . Token . IsCancellationRequested && _listener ? . IsListening == true )
@@ -121,15 +139,16 @@ private JObject GetHealthStatus()
121139 {
122140 var currentHeight = NativeContract . Ledger . CurrentIndex ( _system . StoreView ) ;
123141 var headerHeight = _system . HeaderCache . Last ? . Index ?? currentHeight ;
124- var blocksBehind = headerHeight - currentHeight ;
142+ var blocksBehind = headerHeight >= currentHeight ? headerHeight - currentHeight : 0 ;
125143 var isSynced = blocksBehind <= 2 ;
126- var peerCount = 0 ;
144+ int ? peerCount = _localNode ? . ConnectedCount ;
145+ var hasPeers = peerCount is null || peerCount > 0 ;
127146
128147 var memPool = _system . MemPool ;
129148 var mempoolCount = memPool . Count ;
130149 var mempoolCapacity = memPool . Capacity ;
131150
132- var status = isSynced && peerCount >= 0 ? "healthy" : "degraded" ;
151+ var status = isSynced && hasPeers ? "healthy" : "degraded" ;
133152
134153 return new JObject
135154 {
@@ -147,6 +166,11 @@ private JObject GetHealthStatus()
147166 [ "blocks_behind" ] = blocksBehind ,
148167 [ "synced" ] = isSynced
149168 } ,
169+ [ "network" ] = new JObject
170+ {
171+ [ "status" ] = hasPeers ? "healthy" : "degraded" ,
172+ [ "connected_peers" ] = peerCount ?? 0
173+ } ,
150174 [ "mempool" ] = new JObject
151175 {
152176 [ "status" ] = "healthy" ,
@@ -174,13 +198,19 @@ private JObject GetReadinessStatus()
174198 {
175199 var currentHeight = NativeContract . Ledger . CurrentIndex ( _system . StoreView ) ;
176200 var headerHeight = _system . HeaderCache . Last ? . Index ?? currentHeight ;
177- var isSynced = ( headerHeight - currentHeight ) <= 2 ;
201+ var blocksBehind = headerHeight >= currentHeight ? headerHeight - currentHeight : 0 ;
202+ var isSynced = blocksBehind <= 2 ;
203+ int ? peerCount = _localNode ? . ConnectedCount ;
204+ var hasPeers = peerCount is null || peerCount > 0 ;
205+ var ready = isSynced && hasPeers ;
178206
179207 return new JObject
180208 {
181- [ "status" ] = isSynced ? "healthy" : "not_ready" ,
209+ [ "status" ] = ready ? "healthy" : "not_ready" ,
182210 [ "timestamp" ] = DateTime . UtcNow . ToString ( "O" ) ,
183211 [ "synced" ] = isSynced ,
212+ [ "blocks_behind" ] = blocksBehind ,
213+ [ "connected_peers" ] = peerCount ?? 0 ,
184214 [ "block_height" ] = currentHeight
185215 } ;
186216 }
0 commit comments