-
Notifications
You must be signed in to change notification settings - Fork 545
/
Copy pathdownscale.go
72 lines (63 loc) · 2.4 KB
/
downscale.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// SPDX-License-Identifier: AGPL-3.0-only
package ingester
import (
"net/http"
"github.com/go-kit/log/level"
"github.com/grafana/dskit/services"
"github.com/grafana/mimir/pkg/util"
)
// PrepareInstanceRingDownscaleHandler prepares the ingester ring entry for downscaling. It can mark ingester as read-only
// or set it back to read-write mode.
//
// Following methods are supported:
//
// - GET
// Returns timestamp when ingester ring entry was switched to read-only mode, or 0, if ring entry is not in read-only mode.
//
// - POST
// Switches the ingester ring entry to read-only mode (if it isn't yet), and returns the timestamp when the switch to
// read-only mode happened.
//
// - DELETE
// Sets ingester ring entry back to read-write mode.
func (i *Ingester) PrepareInstanceRingDownscaleHandler(w http.ResponseWriter, r *http.Request) {
// Don't allow callers to change the shutdown configuration while we're in the middle
// of starting or shutting down.
if i.State() != services.Running {
w.WriteHeader(http.StatusServiceUnavailable)
return
}
// If ingest storage is used, don't allow manipulations with instance ring entry.
if i.cfg.IngestStorageConfig.Enabled {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
switch r.Method {
case http.MethodPost:
// Calling this repeatedly doesn't update the read-only timestamp, if instance is already in read-only mode.
err := i.lifecycler.ChangeReadOnlyState(r.Context(), true)
if err != nil {
level.Error(i.logger).Log("msg", "failed to set ingester to read-only mode in the ring", "err", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Deactivate the push circuit breaker in read-only mode. Calling this repeatedly is fine.
i.circuitBreaker.push.deactivate()
case http.MethodDelete:
// Clear the read-only status.
err := i.lifecycler.ChangeReadOnlyState(r.Context(), false)
if err != nil {
level.Error(i.logger).Log("msg", "failed to clear ingester's read-only mode", "err", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Activate the push circuit breaker when exiting read-only mode. Calling this repeatedly is fine.
i.circuitBreaker.push.activate()
}
ro, rots := i.lifecycler.GetReadOnlyState()
if ro {
util.WriteJSONResponse(w, map[string]any{"timestamp": rots.Unix()})
} else {
util.WriteJSONResponse(w, map[string]any{"timestamp": 0})
}
}