@@ -90,6 +90,7 @@ func NewWatcherCommand() *cobra.Command {
9090 cmd .Flags ().StringP ("blockfrost-endpoint" , "" , "" , "blockfrost API endpoint" )
9191 cmd .Flags ().IntP ("blockfrost-max-routines" , "" , 10 , "number of routines used by blockfrost to perform concurrent actions" )
9292 cmd .Flags ().IntP ("blockfrost-timeout" , "" , 60 , "Timeout for requests to the Blockfrost API (in seconds)" )
93+ cmd .Flags ().IntP ("status-watcher-refresh-interval" , "" , 15 , "Interval at which the status watcher collects data about the network (in seconds)" )
9394 cmd .Flags ().BoolP ("network-watcher-enabled" , "" , true , "Enable network watcher" )
9495 cmd .Flags ().IntP ("network-watcher-refresh-interval" , "" , 60 , "Interval at which the network watcher collects data about the network (in seconds)" )
9596 cmd .Flags ().BoolP ("pool-watcher-enabled" , "" , true , "Enable pool watcher" )
@@ -112,10 +113,12 @@ func NewWatcherCommand() *cobra.Command {
112113 checkError (viper .BindPFlag ("blockfrost.timeout" , cmd .Flag ("blockfrost-timeout" )), "unable to bind blockfrost-timeout flag" )
113114 checkError (viper .BindPFlag ("network-watcher.enabled" , cmd .Flag ("network-watcher-enabled" )), "unable to bind network-watcher-enabled flag" )
114115 checkError (viper .BindPFlag ("network-watcher.refresh-interval" , cmd .Flag ("network-watcher-refresh-interval" )), "unable to bind network-watcher-refresh-interval flag" )
116+ checkError (viper .BindPFlag ("status-watcher.refresh-interval" , cmd .Flag ("status-watcher-refresh-interval" )), "unable to bind status-watcher-refresh-interval flag" )
115117 checkError (viper .BindPFlag ("pool-watcher.enabled" , cmd .Flag ("pool-watcher-enabled" )), "unable to bind pool-watcher-enabled flag" )
116118 checkError (viper .BindPFlag ("pool-watcher.refresh-interval" , cmd .Flag ("pool-watcher-refresh-interval" )), "unable to bind pool-watcher-refresh-interval flag" )
117119 checkError (viper .BindPFlag ("block-watcher.enabled" , cmd .Flag ("block-watcher-enabled" )), "unable to bind block-watcher-enabled flag" )
118120 checkError (viper .BindPFlag ("block-watcher.refresh-interval" , cmd .Flag ("block-watcher-refresh-interval" )), "unable to bind block-watcher-refresh-interval flag" )
121+
119122 return cmd
120123}
121124
@@ -197,24 +200,29 @@ func run(_ *cobra.Command, _ []string) error {
197200 return fmt .Errorf ("unable to refresh slot leaders: %w" , err )
198201 }
199202
203+ healthStore := watcher .NewHealthStore ()
204+
200205 // Start HTTP server
201- if err := startHTTPServer (eg , registry ); err != nil {
206+ if err := startHTTPServer (eg , registry , healthStore ); err != nil {
202207 return fmt .Errorf ("unable to start http server: %w" , err )
203208 }
204209
210+ // Start Status Watcher
211+ startStatusWatcher (ctx , eg , cardano , blockfrost , metrics , healthStore )
212+
205213 // Start Pool Watcher
206214 if cfg .PoolWatcherConfig .Enabled {
207- startPoolWatcher (ctx , eg , blockfrost , metrics , cfg .Pools )
215+ startPoolWatcher (ctx , eg , blockfrost , metrics , cfg .Pools , healthStore )
208216 }
209217
210218 // Start Block Watcher
211219 if cfg .BlockWatcherConfig .Enabled {
212- startBlockWatcher (ctx , eg , cardano , blockfrost , slotLeaderService , metrics , cfg .Pools , database .DB )
220+ startBlockWatcher (ctx , eg , cardano , blockfrost , slotLeaderService , metrics , cfg .Pools , database .DB , healthStore )
213221 }
214222
215223 // Start Network Watcher
216224 if cfg .NetworkWatcherConfig .Enabled {
217- startNetworkWatcher (ctx , eg , blockfrost , metrics )
225+ startNetworkWatcher (ctx , eg , blockfrost , metrics , healthStore )
218226 }
219227
220228 <- ctx .Done ()
@@ -259,11 +267,12 @@ func createCardanoClient(blockfrost blockfrost.Client) cardano.CardanoClient {
259267 return cardanocli .NewClient (opts , blockfrost , & cardanocli.RealCommandExecutor {})
260268}
261269
262- func startHTTPServer (eg * errgroup.Group , registry * prometheus.Registry ) error {
270+ func startHTTPServer (eg * errgroup.Group , registry * prometheus.Registry , healthStore * watcher. HealthStore ) error {
263271 var err error
264272
265273 server , err = http .New (
266274 registry ,
275+ healthStore ,
267276 http .WithHost (cfg .HTTP .Host ),
268277 http .WithPort (cfg .HTTP .Port ),
269278 )
@@ -286,13 +295,36 @@ func startHTTPServer(eg *errgroup.Group, registry *prometheus.Registry) error {
286295 return nil
287296}
288297
298+ // startStatusWatcher starts the status watcher service
299+ func startStatusWatcher (
300+ ctx context.Context ,
301+ eg * errgroup.Group ,
302+ cardano cardano.CardanoClient ,
303+ blockfrost blockfrost.Client ,
304+ metrics * metrics.Collection ,
305+ healthStore * watcher.HealthStore ,
306+ ) {
307+ eg .Go (func () error {
308+ statusWatcher := watcher .NewStatusWatcher (blockfrost , cardano , metrics , healthStore )
309+ logger .Info (
310+ "starting watcher" ,
311+ slog .String ("component" , "status-watcher" ),
312+ )
313+ if err := statusWatcher .Start (ctx ); err != nil {
314+ return fmt .Errorf ("unable to start status watcher: %w" , err )
315+ }
316+ return nil
317+ })
318+ }
319+
289320// startPoolWatcher starts the pool watcher service
290321func startPoolWatcher (
291322 ctx context.Context ,
292323 eg * errgroup.Group ,
293324 blockfrost blockfrost.Client ,
294325 metrics * metrics.Collection ,
295326 pools pools.Pools ,
327+ healthStore * watcher.HealthStore ,
296328) {
297329 eg .Go (func () error {
298330 options := watcher.PoolWatcherOptions {
@@ -303,7 +335,7 @@ func startPoolWatcher(
303335 "starting watcher" ,
304336 slog .String ("component" , "pool-watcher" ),
305337 )
306- poolWatcher , err := watcher .NewPoolWatcher (blockfrost , metrics , pools , options )
338+ poolWatcher , err := watcher .NewPoolWatcher (blockfrost , metrics , pools , healthStore , options )
307339 if err != nil {
308340 return fmt .Errorf ("unable to create pool watcher: %w" , err )
309341 }
@@ -314,12 +346,12 @@ func startPoolWatcher(
314346 })
315347}
316348
317- // startNetworkWatcher starts the network watcher service
318349func startNetworkWatcher (
319350 ctx context.Context ,
320351 eg * errgroup.Group ,
321352 blockfrost blockfrost.Client ,
322353 metrics * metrics.Collection ,
354+ healthStore * watcher.HealthStore ,
323355) {
324356 eg .Go (func () error {
325357 options := watcher.NetworkWatcherOptions {
@@ -331,7 +363,7 @@ func startNetworkWatcher(
331363 "starting watcher" ,
332364 slog .String ("component" , "network-watcher" ),
333365 )
334- networkWatcher := watcher .NewNetworkWatcher (blockfrost , metrics , options )
366+ networkWatcher := watcher .NewNetworkWatcher (blockfrost , metrics , healthStore , options )
335367 if err := networkWatcher .Start (ctx ); err != nil {
336368 return fmt .Errorf ("unable to start network watcher: %w" , err )
337369 }
@@ -349,12 +381,13 @@ func startBlockWatcher(
349381 metrics * metrics.Collection ,
350382 pools pools.Pools ,
351383 db * sqlx.DB ,
384+ healthStore * watcher.HealthStore ,
352385) {
353386 eg .Go (func () error {
354387 options := watcher.BlockWatcherOptions {
355388 RefreshInterval : time .Second * time .Duration (cfg .BlockWatcherConfig .RefreshInterval ),
356389 }
357- blockWatcher := watcher .NewBlockWatcher (cardano , blockfrost , sl , pools , metrics , db , options )
390+ blockWatcher := watcher .NewBlockWatcher (cardano , blockfrost , sl , pools , metrics , db , healthStore , options )
358391 logger .Info (
359392 "starting watcher" ,
360393 slog .String ("component" , "block-watcher" ),
0 commit comments