@@ -2,13 +2,15 @@ package verifier
22
33import (
44 "context"
5+ "sync"
6+ "time"
7+
58 "github.com/ethereum/go-ethereum/core/types"
69 "github.com/evstack/ev-metrics/internal/clients/celestia"
710 "github.com/evstack/ev-metrics/internal/clients/evm"
811 "github.com/evstack/ev-metrics/internal/clients/evnode"
912 "github.com/evstack/ev-metrics/pkg/metrics"
1013 "github.com/rs/zerolog"
11- "time"
1214)
1315
1416var _ metrics.Exporter = & exporter {}
@@ -20,6 +22,7 @@ func NewMetricsExporter(
2022 evmClient * evm.Client ,
2123 headerNS , dataNS []byte ,
2224 chainID string ,
25+ workers int ,
2326 logger zerolog.Logger ,
2427) metrics.Exporter {
2528 return & exporter {
@@ -29,6 +32,7 @@ func NewMetricsExporter(
2932 headerNS : headerNS ,
3033 dataNS : dataNS ,
3134 chainID : chainID ,
35+ workers : workers ,
3236 logger : logger .With ().Str ("component" , "verification_monitor" ).Logger (),
3337 }
3438}
@@ -41,6 +45,7 @@ type exporter struct {
4145 headerNS []byte
4246 dataNS []byte
4347 chainID string
48+ workers int
4449 logger zerolog.Logger
4550}
4651
@@ -53,14 +58,33 @@ func (e *exporter) ExportMetrics(ctx context.Context, m *metrics.Metrics) error
5358 }
5459 defer sub .Unsubscribe ()
5560
61+ // create buffered channel for block queue
62+ blockQueue := make (chan * types.Header , e .workers * 2 )
63+
64+ // start work pool
65+ var workerGroup sync.WaitGroup
66+ for i := 0 ; i < e .workers ; i ++ {
67+ workerGroup .Add (1 )
68+ workerID := i
69+ go func () {
70+ defer workerGroup .Done ()
71+ e .processBlocks (ctx , m , workerID , blockQueue )
72+ }()
73+ }
74+
75+ e .logger .Info ().Int ("workers" , e .workers ).Msg ("started verification work pool" )
76+
5677 // ticker to refresh submission duration metric every 10 seconds
5778 refreshTicker := time .NewTicker (10 * time .Second )
5879 defer refreshTicker .Stop ()
5980
81+ // main subscription loop
6082 for {
6183 select {
6284 case <- ctx .Done ():
6385 e .logger .Info ().Msg ("stopping block verification" )
86+ close (blockQueue )
87+ workerGroup .Wait ()
6488 return nil
6589 case <- refreshTicker .C :
6690 // ensure that submission duration is always included in the 60 second window.
@@ -75,12 +99,31 @@ func (e *exporter) ExportMetrics(ctx context.Context, m *metrics.Metrics) error
7599 Time ("arrival_time" , arrivalTime ).
76100 Msg ("received block header from subscription" )
77101
78- // spawn a goroutine to handle this block's retries
79- go e .verifyBlock (ctx , m , header )
102+ // send block to work pool, blocking until space is available
103+ select {
104+ case blockQueue <- header :
105+ // block queued successfully
106+ case <- ctx .Done ():
107+ close (blockQueue )
108+ workerGroup .Wait ()
109+ return nil
110+ }
80111 }
81112 }
82113}
83114
115+ // processBlocks processes blocks from the queue
116+ func (e * exporter ) processBlocks (ctx context.Context , m * metrics.Metrics , workerID int , blockQueue <- chan * types.Header ) {
117+ logger := e .logger .With ().Int ("worker_id" , workerID ).Logger ()
118+ logger .Debug ().Msg ("worker started" )
119+
120+ for header := range blockQueue {
121+ e .verifyBlock (ctx , m , header )
122+ }
123+
124+ logger .Debug ().Msg ("worker stopped" )
125+ }
126+
84127func (e * exporter ) onVerified (m * metrics.Metrics , namespace string , blockHeight , daHeight uint64 , verified bool , submissionDuration time.Duration ) {
85128 if verified {
86129 m .RecordSubmissionDaHeight (e .chainID , namespace , daHeight )
0 commit comments