Skip to content

The method io.kubernetes.client.informer.SharedInformerFactory#sharedIndexInformerFor should ideally be idempotent. #3849

Description

@Sud0x67

Describe the bug
In our service, we utilize the SharedInformerFactory to generate informers. However, we encountered unexpected behavior when invoking it multiple times. Specifically, it returns a new informer for the same apiTypeClass without maintaining it within the internal map named informers. Consequently, when we call the io.kubernetes.client.informer.SharedInformerFactory#startAllRegisteredInformers method, our informer doesn't start as anticipated. The code is as follows:

  public synchronized <ApiType extends KubernetesObject, ApiListType extends KubernetesListObject>
      SharedIndexInformer<ApiType> sharedIndexInformerFor(
          ListerWatcher<ApiType, ApiListType> listerWatcher,
          Class<ApiType> apiTypeClass,
          long resyncPeriodInMillis,
          BiConsumer<Class<ApiType>, Throwable> exceptionHandler) {

    SharedIndexInformer<ApiType> informer =
        new DefaultSharedIndexInformer<>(
            apiTypeClass, listerWatcher, resyncPeriodInMillis, new Cache<>(), exceptionHandler);
    this.informers.putIfAbsent(TypeToken.get(apiTypeClass).getType(), informer);
    return informer;
  }

This is a bit confusing. I don't understand why the factory created it but doesn't keep it. Could someone explain the purpose of this design to me?

Describe the solution you'd like

I believe the factory should retain all the informers it creates, ensuring that when we call startAllRegisteredInformers, the returned informer starts correctly. Alternatively, the method SharedInformerFactory#sharedIndexInformerFor should be idempotent. This means that if we create an informer for the same apiClassType, it should return the initial instance, similar to the behavior observed in the Go client.

func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
	f.lock.Lock()
	defer f.lock.Unlock()

	informerType := reflect.TypeOf(obj)
	informer, exists := f.informers[informerType]
	if exists {
		return informer
	}

	resyncPeriod, exists := f.customResync[informerType]
	if !exists {
		resyncPeriod = f.defaultResync
	}

	informer = newFunc(f.client, resyncPeriod)
	informer.SetTransform(f.transform)
	f.informers[informerType] = informer

	return informer
}

No response

Client Version
e.g. 8.0.2

Kubernetes Version
e.g. 1.19.3

Java Version
e.g. Java11

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    lifecycle/rottenDenotes an issue or PR that has aged beyond stale and will be auto-closed.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions