Skip to content

Commit 1243675

Browse files
committed
Support lazy setup in readiness endpoint
1 parent 8436bf4 commit 1243675

File tree

2 files changed

+101
-2
lines changed

2 files changed

+101
-2
lines changed

pkg/rpc/server/http.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,13 @@ func RegisterCustomHTTPEndpoints(mux *http.ServeMux, s store.Store, pm p2p.P2PRP
9090
}
9191

9292
if cfg.Node.Aggregator {
93+
var maxAllowedDelay time.Duration
94+
if cfg.Node.LazyMode {
95+
maxAllowedDelay = 2 * cfg.Node.LazyBlockInterval.Duration
96+
} else {
97+
maxAllowedDelay = 5 * cfg.Node.BlockTime.Duration
98+
}
9399
timeSinceLastBlock := time.Since(state.LastBlockTime)
94-
maxAllowedDelay := 5 * cfg.Node.BlockTime.Duration
95-
96100
if timeSinceLastBlock > maxAllowedDelay {
97101
http.Error(w, "UNREADY: aggregator not producing blocks at expected rate", http.StatusServiceUnavailable)
98102
return

pkg/rpc/server/http_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import (
55
"net/http"
66
"net/http/httptest"
77
"testing"
8+
"time"
89

910
"github.com/evstack/ev-node/pkg/config"
1011
"github.com/evstack/ev-node/test/mocks"
12+
"github.com/evstack/ev-node/types"
1113
"github.com/rs/zerolog"
1214
"github.com/stretchr/testify/assert"
1315
"github.com/stretchr/testify/mock"
16+
"github.com/stretchr/testify/require"
1417
)
1518

1619
func TestRegisterCustomHTTPEndpoints(t *testing.T) {
@@ -38,3 +41,95 @@ func TestRegisterCustomHTTPEndpoints(t *testing.T) {
3841

3942
mockStore.AssertExpectations(t)
4043
}
44+
45+
func TestHealthReady_aggregatorBlockDelay(t *testing.T) {
46+
ctx := t.Context()
47+
logger := zerolog.Nop()
48+
49+
type spec struct {
50+
name string
51+
lazy bool
52+
blockTime time.Duration
53+
lazyInterval time.Duration
54+
delay time.Duration
55+
expStatusCode int
56+
expBody string
57+
}
58+
59+
specs := map[string]spec{
60+
"aggregator within non-lazy threshold": {
61+
lazy: false,
62+
blockTime: 200 * time.Millisecond,
63+
lazyInterval: 0,
64+
delay: 800 * time.Millisecond, // 5x blockTime = 1s, so 0.8s is OK
65+
expStatusCode: http.StatusOK,
66+
expBody: "READY\n",
67+
},
68+
"aggregator exceeds non-lazy threshold": {
69+
lazy: false,
70+
blockTime: 200 * time.Millisecond,
71+
lazyInterval: 0,
72+
delay: 1500 * time.Millisecond, // > 1s threshold
73+
expStatusCode: http.StatusServiceUnavailable,
74+
expBody: "UNREADY: aggregator not producing blocks at expected rate\n",
75+
},
76+
"aggregator within lazy threshold": {
77+
lazy: true,
78+
blockTime: 0,
79+
lazyInterval: 300 * time.Millisecond,
80+
delay: 500 * time.Millisecond, // 2x lazyInterval = 600ms, so 0.5s is OK
81+
expStatusCode: http.StatusOK,
82+
expBody: "READY\n",
83+
},
84+
"aggregator exceeds lazy threshold": {
85+
lazy: true,
86+
blockTime: 0,
87+
lazyInterval: 300 * time.Millisecond,
88+
delay: 800 * time.Millisecond, // > 600ms threshold
89+
expStatusCode: http.StatusServiceUnavailable,
90+
expBody: "UNREADY: aggregator not producing blocks at expected rate\n",
91+
},
92+
}
93+
94+
for name, tc := range specs {
95+
t.Run(name, func(t *testing.T) {
96+
mux := http.NewServeMux()
97+
98+
cfg := config.DefaultConfig()
99+
cfg.Node.Aggregator = true
100+
if tc.blockTime > 0 {
101+
cfg.Node.BlockTime = config.DurationWrapper{Duration: tc.blockTime}
102+
}
103+
cfg.Node.LazyMode = tc.lazy
104+
if tc.lazy {
105+
cfg.Node.LazyBlockInterval = config.DurationWrapper{Duration: tc.lazyInterval}
106+
}
107+
108+
mockStore := mocks.NewMockStore(t)
109+
state := types.State{
110+
LastBlockHeight: 10,
111+
LastBlockTime: time.Now().Add(-tc.delay),
112+
}
113+
mockStore.On("GetState", mock.Anything).Return(state, nil)
114+
115+
bestKnownHeightProvider := func() uint64 { return state.LastBlockHeight }
116+
117+
RegisterCustomHTTPEndpoints(mux, mockStore, nil, cfg, bestKnownHeightProvider, logger)
118+
119+
ts := httptest.NewServer(mux)
120+
t.Cleanup(ts.Close)
121+
122+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ts.URL+"/health/ready", nil)
123+
require.NoError(t, err)
124+
resp, err := http.DefaultClient.Do(req)
125+
require.NoError(t, err)
126+
t.Cleanup(func() { _ = resp.Body.Close() })
127+
128+
body, err := io.ReadAll(resp.Body)
129+
require.NoError(t, err)
130+
131+
assert.Equal(t, tc.expStatusCode, resp.StatusCode)
132+
assert.Equal(t, tc.expBody, string(body))
133+
})
134+
}
135+
}

0 commit comments

Comments
 (0)