Skip to content

Commit 61820cf

Browse files
committed
refactor: don't require anything object-specific at handler construction
this avoids recomputing the entire handler state machine on each sync
1 parent de9b6dc commit 61820cf

File tree

7 files changed

+36
-25
lines changed

7 files changed

+36
-25
lines changed

component.go

+12-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package libctrl
22

33
import (
4+
"context"
45
"fmt"
56

67
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -20,24 +21,24 @@ type KubeObject interface {
2021
// i.e. a pod would be a component of a deployment (though direct ownership is
2122
// not required).
2223
type Component[K KubeObject] struct {
23-
indexer *typed.Indexer[K]
24-
selector labels.Selector
25-
indexName string
24+
indexer *typed.Indexer[K]
25+
selectorFunc func(ctx context.Context) labels.Selector
26+
indexName string
2627
}
2728

2829
// NewIndexedComponent creates a component from an index
29-
func NewIndexedComponent[K KubeObject](indexer *typed.Indexer[K], indexName string, selector labels.Selector) *Component[K] {
30+
func NewIndexedComponent[K KubeObject](indexer *typed.Indexer[K], indexName string, selectorFunc func(ctx context.Context) labels.Selector) *Component[K] {
3031
return &Component[K]{
31-
indexer: indexer,
32-
indexName: indexName,
33-
selector: selector,
32+
indexer: indexer,
33+
indexName: indexName,
34+
selectorFunc: selectorFunc,
3435
}
3536
}
3637

3738
// List all objects that match the component's specification.
3839
// Components are expected to be unique (per label), but List returns a slice
3940
// so that controllers can handle duplicates appropriately.
40-
func (c *Component[K]) List(indexValue fmt.Stringer) (out []K) {
41+
func (c *Component[K]) List(ctx context.Context, indexValue fmt.Stringer) (out []K) {
4142
out = make([]K, 0)
4243
ownedObjects, err := c.indexer.ByIndex(c.indexName, indexValue.String())
4344
if err != nil {
@@ -49,7 +50,7 @@ func (c *Component[K]) List(indexValue fmt.Stringer) (out []K) {
4950
if ls == nil {
5051
continue
5152
}
52-
if c.selector.Matches(labels.Set(ls)) {
53+
if c.selectorFunc(ctx).Matches(labels.Set(ls)) {
5354
out = append(out, d)
5455
}
5556
}
@@ -59,12 +60,12 @@ func (c *Component[K]) List(indexValue fmt.Stringer) (out []K) {
5960
// HashableComponent is a Component with an annotation that stores a hash of the
6061
// previous configuration the controller wrote
6162
type HashableComponent[K KubeObject] struct {
62-
Component[K]
63+
*Component[K]
6364
ObjectHasher
6465
HashAnnotationKey string
6566
}
6667

67-
func NewHashableComponent[K KubeObject](component Component[K], hasher ObjectHasher, key string) *HashableComponent[K] {
68+
func NewHashableComponent[K KubeObject](component *Component[K], hasher ObjectHasher, key string) *HashableComponent[K] {
6869
return &HashableComponent[K]{
6970
Component: component,
7071
ObjectHasher: hasher,

component_handler.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,22 @@ package libctrl
22

33
import (
44
"context"
5-
"fmt"
5+
6+
"k8s.io/apimachinery/pkg/types"
67

78
"github.com/authzed/controller-idioms/handler"
89
)
910

1011
// ComponentContextHandler fills the value for a ContextKey with the result of
1112
// fetching a component.
1213
type ComponentContextHandler[K KubeObject] struct {
13-
owner fmt.Stringer
14+
owner MustValueContext[types.NamespacedName]
1415
ctxKey SettableContext[[]K]
1516
component *Component[K]
1617
next handler.ContextHandler
1718
}
1819

19-
func NewComponentContextHandler[K KubeObject](contextKey SettableContext[[]K], component *Component[K], owner fmt.Stringer, next handler.ContextHandler) *ComponentContextHandler[K] {
20+
func NewComponentContextHandler[K KubeObject](contextKey SettableContext[[]K], component *Component[K], owner MustValueContext[types.NamespacedName], next handler.ContextHandler) *ComponentContextHandler[K] {
2021
return &ComponentContextHandler[K]{
2122
owner: owner,
2223
ctxKey: contextKey,
@@ -26,6 +27,6 @@ func NewComponentContextHandler[K KubeObject](contextKey SettableContext[[]K], c
2627
}
2728

2829
func (h *ComponentContextHandler[K]) Handle(ctx context.Context) {
29-
ctx = h.ctxKey.WithValue(ctx, h.component.List(h.owner))
30+
ctx = h.ctxKey.WithValue(ctx, h.component.List(ctx, h.owner.MustValue(ctx)))
3031
h.next.Handle(ctx)
3132
}

ensure_component.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,20 @@ type Annotator[T any] interface {
1717
type EnsureComponentByHash[K KubeObject, A Annotator[A]] struct {
1818
*HashableComponent[K]
1919
ctrls *ContextKey[ControlAll]
20-
nn types.NamespacedName
20+
nn MustValueContext[types.NamespacedName]
2121
applyObject func(ctx context.Context, apply A) (K, error)
22-
deleteObject func(ctx context.Context, name string) error
22+
deleteObject func(ctx context.Context, nn types.NamespacedName) error
2323
newObj func(ctx context.Context) A
2424
}
2525

2626
var _ handler.ContextHandler = &EnsureComponentByHash[*corev1.Service, *applycorev1.ServiceApplyConfiguration]{}
2727

2828
func NewEnsureComponentByHash[K KubeObject, A Annotator[A]](
2929
component *HashableComponent[K],
30-
owner types.NamespacedName,
30+
owner MustValueContext[types.NamespacedName],
3131
ctrls *ContextKey[ControlAll],
3232
applyObj func(ctx context.Context, apply A) (K, error),
33-
deleteObject func(ctx context.Context, name string) error,
33+
deleteObject func(ctx context.Context, nn types.NamespacedName) error,
3434
newObj func(ctx context.Context) A,
3535
) *EnsureComponentByHash[K, A] {
3636
return &EnsureComponentByHash[K, A]{
@@ -44,7 +44,7 @@ func NewEnsureComponentByHash[K KubeObject, A Annotator[A]](
4444
}
4545

4646
func (e *EnsureComponentByHash[K, A]) Handle(ctx context.Context) {
47-
ownedObjs := e.List(e.nn)
47+
ownedObjs := e.List(ctx, e.nn.MustValue(ctx))
4848

4949
newObj := e.newObj(ctx)
5050
hash, err := e.Hash(newObj)
@@ -80,7 +80,10 @@ func (e *EnsureComponentByHash[K, A]) Handle(ctx context.Context) {
8080
if len(matchingObjs) == 1 {
8181
// delete extra objects
8282
for _, o := range extraObjs {
83-
if err := e.deleteObject(ctx, o.GetName()); err != nil {
83+
if err := e.deleteObject(ctx, types.NamespacedName{
84+
Namespace: o.GetNamespace(),
85+
Name: o.GetName(),
86+
}); err != nil {
8487
e.ctrls.MustValue(ctx).RequeueErr(err)
8588
return
8689
}

file_informer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func NewFileInformer(watcher *fsnotify.Watcher, gvr schema.GroupVersionResource)
105105
return &FileInformer{
106106
fileName: gvr.Resource,
107107
watcher: watcher,
108-
informer: NewFileSharedIndexInformer(gvr.Resource, watcher, 15*time.Minute),
108+
informer: NewFileSharedIndexInformer(gvr.Resource, watcher, 1*time.Minute),
109109
}, nil
110110
}
111111

handler/handler.go

+6
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ func (h Handlers) MustOne() Handler {
100100
return h[0]
101101
}
102102

103+
// NewTypeHandler assigns an id based on the underlying type to a ContextHandler
104+
// implementation and returns a Handler.
105+
func NewTypeHandler(h ContextHandler) Handler {
106+
return Handler{ContextHandler: h, id: Key(fmt.Sprintf("%T", h))}
107+
}
108+
103109
// NewHandler assigns an id to a ContextHandler implementation and returns a
104110
// Handler.
105111
func NewHandler(h ContextHandler, id Key) Handler {

manager/controller.go

+2
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,12 @@ func (c *OwnedResourceController) processNext(ctx context.Context) bool {
131131
ctx, cancel := context.WithCancel(ctx)
132132

133133
done := func() {
134+
klog.FromContext(ctx).V(5).Info("done", "key", key)
134135
cancel()
135136
c.Queue.Forget(key)
136137
}
137138
requeue := func(after time.Duration) {
139+
klog.FromContext(ctx).V(5).Info("requeue", "key", key, "after", after)
138140
cancel()
139141
if after == 0 {
140142
c.Queue.AddRateLimited(key)

pause.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type PauseHandler[K HasStatusConditions] struct {
4242
Next handler.ContextHandler
4343
}
4444

45-
func NewPauseHandler[K HasStatusConditions](ctrls *ContextKey[ControlAll],
45+
func NewPauseContextHandler[K HasStatusConditions](ctrls *ContextKey[ControlAll],
4646
pausedLabelKey string,
4747
object *ContextDefaultingKey[K],
4848
patchStatus func(ctx context.Context, patch K) error,
@@ -94,14 +94,12 @@ type SelfPauseHandler[K HasStatusConditions] struct {
9494
func NewSelfPauseHandler[K HasStatusConditions](ctrls *ContextKey[ControlAll],
9595
pausedLabelKey string,
9696
contextKey *ContextDefaultingKey[K],
97-
ownerUID types.UID,
9897
patch, patchStatus func(ctx context.Context, patch K) error,
9998
) *SelfPauseHandler[K] {
10099
return &SelfPauseHandler[K]{
101100
CtxKey: contextKey,
102101
ctrls: ctrls,
103102
PausedLabelKey: pausedLabelKey,
104-
OwnerUID: ownerUID,
105103
Patch: patch,
106104
PatchStatus: patchStatus,
107105
}

0 commit comments

Comments
 (0)