Skip to content

Commit f74b4cd

Browse files
authored
Fixed ingester ReadOnly state related bugs (#6208)
Signed-off-by: Alex Le <[email protected]>
1 parent 2490796 commit f74b4cd

File tree

5 files changed

+71
-2
lines changed

5 files changed

+71
-2
lines changed

pkg/ingester/http_admin.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const tpl = `
4343
{{ range .Stats }}
4444
<tr>
4545
<td>{{ .UserID }}</td>
46-
<td align='right'>{{ .UserStats.LoadBlocks }}</td>
46+
<td align='right'>{{ .UserStats.LoadedBlocks }}</td>
4747
<td align='right'>{{ .UserStats.NumSeries }}</td>
4848
<td align='right'>{{ .UserStats.ActiveSeries }}</td>
4949
<td align='right'>{{ printf "%.2f" .UserStats.IngestionRate }}</td>

pkg/ingester/http_admin_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package ingester
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestUserStatsPageRendered(t *testing.T) {
12+
req := httptest.NewRequest(http.MethodGet, "/ingester/all_user_stats", nil)
13+
res := httptest.NewRecorder()
14+
userStats := []UserIDStats{
15+
{
16+
UserID: "123",
17+
UserStats: UserStats{
18+
IngestionRate: 11.11,
19+
NumSeries: 2222,
20+
APIIngestionRate: 33.33,
21+
RuleIngestionRate: 44.44,
22+
ActiveSeries: 5555,
23+
LoadedBlocks: 6666,
24+
},
25+
},
26+
}
27+
AllUserStatsRender(res, req, userStats, 3)
28+
assert.Equal(t, http.StatusOK, res.Code)
29+
body := res.Body.String()
30+
assert.Regexp(t, "<td.+123.+/td>", body)
31+
assert.Regexp(t, "<td.+11.11.+/td>", body)
32+
assert.Regexp(t, "<td.+2222.+/td>", body)
33+
assert.Regexp(t, "<td.+33.33.+/td>", body)
34+
assert.Regexp(t, "<td.+44.44.+/td>", body)
35+
assert.Regexp(t, "<td.+5555.+/td>", body)
36+
assert.Regexp(t, "<td.+6666.+/td>", body)
37+
}

pkg/ingester/ingester_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -5206,20 +5206,23 @@ func Test_Ingester_ModeHandler(t *testing.T) {
52065206
mode string
52075207
expectedState ring.InstanceState
52085208
expectedResponse int
5209+
expectedIsReady bool
52095210
}{
52105211
"should change to READONLY mode": {
52115212
method: "POST",
52125213
initialState: ring.ACTIVE,
52135214
requestUrl: "/mode?mode=reAdOnLy",
52145215
expectedState: ring.READONLY,
52155216
expectedResponse: http.StatusOK,
5217+
expectedIsReady: true,
52165218
},
52175219
"should change mode on GET method": {
52185220
method: "GET",
52195221
initialState: ring.ACTIVE,
52205222
requestUrl: "/mode?mode=READONLY",
52215223
expectedState: ring.READONLY,
52225224
expectedResponse: http.StatusOK,
5225+
expectedIsReady: true,
52235226
},
52245227
"should change mode on POST method via body": {
52255228
method: "POST",
@@ -5228,53 +5231,61 @@ func Test_Ingester_ModeHandler(t *testing.T) {
52285231
requestBody: strings.NewReader("mode=readonly"),
52295232
expectedState: ring.READONLY,
52305233
expectedResponse: http.StatusOK,
5234+
expectedIsReady: true,
52315235
},
52325236
"should change to ACTIVE mode": {
52335237
method: "POST",
52345238
initialState: ring.READONLY,
52355239
requestUrl: "/mode?mode=active",
52365240
expectedState: ring.ACTIVE,
52375241
expectedResponse: http.StatusOK,
5242+
expectedIsReady: true,
52385243
},
52395244
"should fail to unknown mode": {
52405245
method: "POST",
52415246
initialState: ring.ACTIVE,
52425247
requestUrl: "/mode?mode=NotSupported",
52435248
expectedState: ring.ACTIVE,
52445249
expectedResponse: http.StatusBadRequest,
5250+
expectedIsReady: true,
52455251
},
52465252
"should maintain in readonly": {
52475253
method: "POST",
52485254
initialState: ring.READONLY,
52495255
requestUrl: "/mode?mode=READONLY",
52505256
expectedState: ring.READONLY,
52515257
expectedResponse: http.StatusOK,
5258+
expectedIsReady: true,
52525259
},
52535260
"should maintain in active": {
52545261
method: "POST",
52555262
initialState: ring.ACTIVE,
52565263
requestUrl: "/mode?mode=ACTIVE",
52575264
expectedState: ring.ACTIVE,
52585265
expectedResponse: http.StatusOK,
5266+
expectedIsReady: true,
52595267
},
52605268
"should fail mode READONLY if LEAVING state": {
52615269
method: "POST",
52625270
initialState: ring.LEAVING,
52635271
requestUrl: "/mode?mode=READONLY",
52645272
expectedState: ring.LEAVING,
52655273
expectedResponse: http.StatusBadRequest,
5274+
expectedIsReady: false,
52665275
},
52675276
"should fail with malformatted request": {
52685277
method: "GET",
52695278
initialState: ring.ACTIVE,
52705279
requestUrl: "/mode?mod;e=READONLY",
52715280
expectedResponse: http.StatusBadRequest,
5281+
expectedIsReady: true,
52725282
},
52735283
}
52745284

52755285
for testName, testData := range tests {
52765286
t.Run(testName, func(t *testing.T) {
52775287
cfg := defaultIngesterTestConfig(t)
5288+
cfg.LifecyclerConfig.MinReadyDuration = 0
52785289
i, err := prepareIngesterWithBlocksStorage(t, cfg, prometheus.NewRegistry())
52795290
require.NoError(t, err)
52805291
require.NoError(t, services.StartAndAwaitRunning(context.Background(), i))
@@ -5304,6 +5315,13 @@ func Test_Ingester_ModeHandler(t *testing.T) {
53045315

53055316
require.Equal(t, testData.expectedResponse, response.Code)
53065317
require.Equal(t, testData.expectedState, i.lifecycler.GetState())
5318+
5319+
err = i.CheckReady(context.Background())
5320+
if testData.expectedIsReady {
5321+
require.NoError(t, err)
5322+
} else {
5323+
require.NotNil(t, err)
5324+
}
53075325
})
53085326
}
53095327
}

pkg/ring/model.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func (i *InstanceDesc) IsReady(storageLastUpdated time.Time, heartbeatTimeout ti
153153
if !i.IsHeartbeatHealthy(heartbeatTimeout, storageLastUpdated) {
154154
return fmt.Errorf("instance %s past heartbeat timeout", i.Addr)
155155
}
156-
if i.State != ACTIVE {
156+
if i.State != ACTIVE && i.State != READONLY {
157157
return fmt.Errorf("instance %s in state %v", i.Addr, i.State)
158158
}
159159
return nil

pkg/ring/model_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,20 @@ func TestDesc_Ready(t *testing.T) {
275275
if err := r.IsReady(now, 10*time.Second); err != nil {
276276
t.Fatal("expected ready, got", err)
277277
}
278+
279+
r = &Desc{
280+
Ingesters: map[string]InstanceDesc{
281+
"ing1": {
282+
Tokens: []uint32{100, 200, 300},
283+
State: READONLY,
284+
Timestamp: now.Unix(),
285+
},
286+
},
287+
}
288+
289+
if err := r.IsReady(now, 10*time.Second); err != nil {
290+
t.Fatal("expected readonly ingester as ready, but got", err)
291+
}
278292
}
279293

280294
func TestDesc_getTokensByZone(t *testing.T) {

0 commit comments

Comments
 (0)