add retry func for reconciler (#1008)

* add retry func for reconciler

* run update_deps.sh properly

* review comments

* review comments
This commit is contained in:
Nicolas Lopez 2020-01-27 10:22:26 -05:00 committed by Knative Prow Robot
parent 5ff923b836
commit 4252f595d1
3 changed files with 107 additions and 0 deletions

2
Gopkg.lock generated
View File

@ -1393,6 +1393,7 @@
"k8s.io/api/admissionregistration/v1beta1",
"k8s.io/api/apps/v1",
"k8s.io/api/authentication/v1",
"k8s.io/api/autoscaling/v1",
"k8s.io/api/autoscaling/v2beta1",
"k8s.io/api/batch/v1",
"k8s.io/api/core/v1",
@ -1449,6 +1450,7 @@
"k8s.io/client-go/tools/clientcmd",
"k8s.io/client-go/tools/metrics",
"k8s.io/client-go/tools/record",
"k8s.io/client-go/util/retry",
"k8s.io/client-go/util/workqueue",
"k8s.io/code-generator/cmd/client-gen",
"k8s.io/code-generator/cmd/client-gen/generators/util",

28
reconciler/retry.go Normal file
View File

@ -0,0 +1,28 @@
/*
Copyright 2020 The Knative Authors
Licensed under the Apache License, Veroute.on 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package reconciler
import (
"k8s.io/client-go/util/retry"
)
// RetryUpdateConflicts retries the inner function if it returns conflict errors.
// This can be used to retry status updates without constantly reenqueuing keys.
func RetryUpdateConflicts(updater func(int) error) error {
attempts := 0
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
err := updater(attempts)
attempts++
return err
})
}

77
reconciler/retry_test.go Normal file
View File

@ -0,0 +1,77 @@
/*
Copyright 2020 The Knative Authors
Licensed under the Apache License, Veroute.on 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package reconciler
import (
"errors"
"testing"
apierrs "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/api/autoscaling/v1"
)
func TestRetryUpdateConflicts(t *testing.T) {
errAny := errors.New("foo")
errConflict := apierrs.NewConflict(v1.Resource("foo"), "bar", errAny)
tests := []struct {
name string
returns []error
want error
wantAttempts int
}{{
name: "all good",
returns: []error{nil},
want: nil,
wantAttempts: 1,
}, {
name: "not retry on non-conflict error",
returns: []error{errAny},
want: errAny,
wantAttempts: 1,
}, {
name: "retry up to 5 times on conflicts",
returns: []error{errConflict, errConflict, errConflict, errConflict, errConflict, errConflict},
want: errConflict,
wantAttempts: 5,
}, {
name: "eventually succeed",
returns: []error{errConflict, errConflict, nil},
want: nil,
wantAttempts: 3,
}, {
name: "eventually fail",
returns: []error{errConflict, errConflict, errAny},
want: errAny,
wantAttempts: 3,
}}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
attempts := 0
got := RetryUpdateConflicts(func(i int) error {
attempts++
return test.returns[i]
})
if got != test.want {
t.Errorf("RetryUpdateConflicts() = %v, want %v", got, test.want)
}
if attempts != test.wantAttempts {
t.Errorf("attempts = %d, want %d", attempts, test.wantAttempts)
}
})
}
}