Skip to content

Commit

Permalink
reconciler: Prune after initialized even with empty table
Browse files Browse the repository at this point in the history
Pruning should be performed when the table has initialized even
when the table is empty. Use a 1 second ticker time until table
has initialized and pruned and then switch to normal prune interval.

Signed-off-by: Jussi Maki <[email protected]>
  • Loading branch information
joamaki committed Aug 20, 2024
1 parent f97a090 commit 6e328ba
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 12 deletions.
30 changes: 25 additions & 5 deletions reconciler/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,18 @@ func (r *reconciler[Obj]) Prune() {
}

func (r *reconciler[Obj]) reconcileLoop(ctx context.Context, health cell.Health) error {
var pruneTickerChan <-chan time.Time
var (
pruneTickerChan <-chan time.Time
pruneTicker *time.Ticker
)

// If pruning is enabled, start a ticker to initiate the pruning
// Since we want to prune soon after the table has initialized even when it is empty,
// use a 1 second ticker until we've done the initial pruning after which we switch to
// the configured prune interval.

if r.config.PruneInterval > 0 {
pruneTicker := time.NewTicker(r.config.PruneInterval)
pruneTicker = time.NewTicker(time.Second)
defer pruneTicker.Stop()
pruneTickerChan = pruneTicker.C
}
Expand All @@ -55,15 +64,17 @@ func (r *reconciler[Obj]) reconcileLoop(ctx context.Context, health cell.Health)
return err
}
prune := false
retries := false
tableChanged := false

// Wait for trigger
select {
case <-ctx.Done():
return ctx.Err()
case <-r.retries.Wait():
// Object(s) are ready to be retried
retries = true
case <-tableWatchChan:
// Table has changed
tableChanged = true
case <-pruneTickerChan:
prune = true
case <-r.externalPruneTrigger:
Expand All @@ -77,7 +88,10 @@ func (r *reconciler[Obj]) reconcileLoop(ctx context.Context, health cell.Health)

// Perform incremental reconciliation and retries of previously failed
// objects.
errs := r.incremental(ctx, txn, changes)
var errs []error
if retries || tableChanged {
errs = r.incremental(ctx, txn, changes)
}

if !tableInitialized {
if r.config.Table.Initialized(txn) {
Expand All @@ -86,6 +100,12 @@ func (r *reconciler[Obj]) reconcileLoop(ctx context.Context, health cell.Health)
// Do an immediate pruning now as the table has finished
// initializing and pruning is enabled.
prune = r.config.PruneInterval != 0

// Reconfigure the ticker to do the next pruning with the
// configured interval.
if r.config.PruneInterval > 0 {
pruneTicker.Reset(r.config.PruneInterval)
}
} else {
// Table not initialized yet, skip this pruning round.
prune = false
Expand Down
25 changes: 18 additions & 7 deletions reconciler/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,14 @@ func testReconciler(t *testing.T, batchOps bool) {
h.triggerPrune()
h.expectOp(opUpdate(ID_1))
h.expectHealth(cell.StatusOK, "OK, 1 object(s)", "")
h.markInitialized()

// After initialization we expect to see pruning immediately
// as soon as something changes. Marking the table initialized
// does not yet trigger the reconciler since it's waiting for
// objects to change.
h.insert(ID_2, NonFaulty, reconciler.StatusPending())
h.expectOps(opUpdate(ID_2), opPrune(2))
h.expectOp(opUpdate(ID_2))
h.expectHealth(cell.StatusOK, "OK, 2 object(s)", "")

// After initialization we expect to see pruning immediately.
h.markInitialized()
h.expectOps(opPrune(2))

// Pruning can be now triggered at will.
h.triggerPrune()
h.expectOps(opUpdate(ID_2), opPrune(2), opPrune(2))
Expand Down Expand Up @@ -304,6 +302,19 @@ func testReconciler(t *testing.T, batchOps bool) {
assert.Equal(t, getInt(h.m.PruneCurrentErrorsVar.Get("test")), int64(0), "PruneCurrentErrors")
})

runTest("pruning-empty-table",
[]reconciler.Option{
reconciler.WithPruning(100 * time.Millisecond),
},
func(h testHelper) {
// Mark the table initialized. This should trigger the pruning
// even when there are no objects.
h.markInitialized()

// Expect to see the initial pruning and then periodic pruning.
h.expectOps(opPrune(0), opPrune(0))
})

runTest("refreshing",
[]reconciler.Option{
reconciler.WithPruning(0), // Disable
Expand Down

0 comments on commit 6e328ba

Please sign in to comment.