Skip to content

Commit 264bad4

Browse files
feat: add retrying k8s client implementation (#79)
* add retrying k8s client implementation * implement review feedback * try approach without reflection * add possibility to inject context for cancellation into GroupVersionKindForObject and IsObjectNamespaced --------- Co-authored-by: Valentin Gerlach <valentin.gerlach@sap.com>
1 parent fc8d26a commit 264bad4

File tree

6 files changed

+802
-1
lines changed

6 files changed

+802
-1
lines changed

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- [Key-Value Pairs](libs/pairs.md)
1515
- [Readiness Checks](libs/readiness.md)
1616
- [Kubernetes Resource Management](libs/resource.md)
17+
- [Retrying k8s Operations](libs/retry.md)
1718
- [Kubernetes Resource Status Updating](libs/status.md)
1819
- [Testing](libs/testing.md)
1920
- [Thread Management](libs/threads.md)

docs/libs/retry.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Retrying k8s Operations
2+
3+
The `pkg/retry` package contains a `Client` that wraps a `client.Client` while implementing the interface itself and retries any failed (= the returned error is not `nil`) operation.
4+
Methods that don't return an error are simply forwarded to the internal client.
5+
6+
In addition to the `client.Client` interface's methods, the `retry.Client` also has `CreateOrUpdate` and `CreateOrPatch` methods, which use the corresponding controller-runtime implementations internally.
7+
8+
The default retry parameters are:
9+
- retry every 100 milliseconds
10+
- don't increase retry interval
11+
- no maximum number of attempts
12+
- timeout after 1 second
13+
14+
The `retry.Client` struct has builder-style methods to configure the parameters:
15+
```golang
16+
retryingClient := retry.NewRetryingClient(myClient).
17+
WithTimeout(10 * time.Second). // try for at max 10 seconds
18+
WithInterval(500 * time.Millisecond). // try every 500 milliseconds, but ...
19+
WithBackoffMultiplier(2.0) // ... double the interval after each retry
20+
```
21+
22+
For convenience, the `clusters.Cluster` type can return a retrying client for its internal client:
23+
```golang
24+
// cluster is of type *clusters.Cluster
25+
err := cluster.Retry().WithMaxAttempts(3).Get(...)
26+
```

pkg/clusters/cluster.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"sigs.k8s.io/controller-runtime/pkg/cluster"
1313

1414
"github.com/openmcp-project/controller-utils/pkg/controller"
15+
"github.com/openmcp-project/controller-utils/pkg/retry"
1516
)
1617

1718
type Cluster struct {
@@ -238,6 +239,12 @@ func (c *Cluster) APIServerEndpoint() string {
238239
return c.restCfg.Host
239240
}
240241

242+
// Retry returns a retrying client for the cluster.
243+
// Returns nil if the client has not been initialized.
244+
func (c *Cluster) Retry() *retry.Client {
245+
return retry.NewRetryingClient(c.Client())
246+
}
247+
241248
/////////////////
242249
// Serializing //
243250
/////////////////

pkg/pairs/pairs_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
func TestConditions(t *testing.T) {
1515
RegisterFailHandler(Fail)
1616

17-
RunSpecs(t, "ClusterAccess Test Suite")
17+
RunSpecs(t, "Pairs Test Suite")
1818
}
1919

2020
type comparableIntAlias int

0 commit comments

Comments
 (0)