4
4
"context"
5
5
"errors"
6
6
"fmt"
7
+ "sync"
7
8
"time"
8
9
9
10
"github.com/coder/quartz"
@@ -27,8 +28,9 @@ const (
27
28
RingKey = "ingest-limits"
28
29
RingName = "ingest-limits"
29
30
30
- // Readiness check
31
- maxPartitionReadinessAttempts int32 = 10
31
+ // The maximum number of checks to fail while waiting to be assigned
32
+ // some partitions before giving up and going ready.
33
+ maxPartitionReadinessWaitAssignChecks = 10
32
34
)
33
35
34
36
// Service is a service that manages stream metadata limits.
@@ -52,9 +54,9 @@ type Service struct {
52
54
streamEvictionsTotal * prometheus.CounterVec
53
55
54
56
// Readiness check
55
- partitionReadinessAttempts int
56
- partitionReadinessPassed bool
57
- partitionReadinessMtx sync.Mutex
57
+ partitionReadinessWaitAssignChecks int
58
+ partitionReadinessPassed bool
59
+ partitionReadinessMtx sync.Mutex
58
60
59
61
// Used for tests.
60
62
clock quartz.Clock
@@ -192,27 +194,31 @@ func (s *Service) CheckReady(ctx context.Context) error {
192
194
if err := s .lifecycler .CheckReady (ctx ); err != nil {
193
195
return fmt .Errorf ("lifecycler not ready: %w" , err )
194
196
}
195
- // Check if the partitions assignment and replay
196
- // are complete on the service startup only.
197
197
s .partitionReadinessMtx .Lock ()
198
198
defer s .partitionReadinessMtx .Unlock ()
199
+ // We are ready when all of our assigned partitions have replayed the
200
+ // last active window of data. This is referred to as partition readiness.
201
+ // Once we have passed partition readiness we never check it again as
202
+ // otherwise the service could become unready during a partition rebalance.
199
203
if ! s .partitionReadinessPassed {
200
- if len (s .partitionManager .List ()) == 0 {
201
- if s .partitionReadinessAttempts >= maxPartitionReadinessAttempts {
202
- // If no partition assigment on startup,
203
- // declare the service initialized.
204
+ if s .partitionManager .Count () == 0 {
205
+ // If partition readiness, once passed, is never checked again,
206
+ // we can assume that the service has recently started and is
207
+ // trying to become ready for the first time. If we do not have
208
+ // any assigned partitions we should wait some time in case we
209
+ // eventually get assigned some partitions, and if not, we give
210
+ // give up and become ready to guarantee liveness.
211
+ s .partitionReadinessWaitAssignChecks ++
212
+ if s .partitionReadinessWaitAssignChecks > maxPartitionReadinessWaitAssignChecks {
213
+ level .Warn (s .logger ).Log ("msg" , "no partitions assigned, going ready" )
204
214
s .partitionReadinessPassed = true
205
- level .Warn (s .logger ).Log ("msg" , "no partitions assigned after max retries, going ready" )
206
215
return nil
207
216
}
208
- s .partitionReadinessAttempts ++
209
- return fmt .Errorf ("no partitions assigned, retrying" )
217
+ return fmt .Errorf ("waiting initial period to be assigned some partitions" )
210
218
}
211
219
if ! s .partitionManager .CheckReady () {
212
- return fmt .Errorf ("partitions not ready" )
220
+ return fmt .Errorf ("partitions are not ready" )
213
221
}
214
- // If the partitions are assigned, and the replay is complete,
215
- // declare the service initialized.
216
222
s .partitionReadinessPassed = true
217
223
}
218
224
return nil
0 commit comments