<p>I'm trying to use client-go informers to get the replica count on deployments. Whenever autoscaling changes the number of replicas, I need to retrieve this in order to handle some other logic. I was previously using the Watch() function, but there are a few inconsistencies with timeouts and connection drops.</p>
<p>The following code below shows an example of the implementation:</p>
<pre><code>labelOptions := informers.WithTweakListOptions(func(opts *v1.ListOptions) {
    opts.FieldSelector = &quot;metadata.name=&quot; + name
})
factory := informers.NewSharedInformerFactoryWithOptions(clientSet, 2*time.Second, informers.WithNamespace(namespace), labelOptions)
informer := factory.Apps().V1().Deployments().Informer()

// Using the channels and goroutines below didn't show changes:
stopper := make(chan struct{})
defer close(stopper)
//go func() {
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) {
        mObj, ok := obj.(*appsv1.Deployment)
        if !ok {
            panic(spew.Sdump(&quot;informer returned invalid type&quot;, mObj))
        }

        replicas := int(*mObj.Spec.Replicas)
        logger.Infof(&quot;updating replicas to %d&quot;, replicas)

        sendUpdates() // use updates elsewhere
    },

    
    UpdateFunc: func(oldObj, newObj interface{}) {
        old, ok := oldObj.(*appsv1.Deployment)
        if !ok {
            panic(spew.Sdump(&quot;informer returned invalid type&quot;, old))
        }
        newDeployment, ok := newObj.(*appsv1.Deployment)
        if !ok {
            panic(spew.Sdump(&quot;informer returned invalid type&quot;, newDeployment))
        }
        oldReplicas := int(*old.Spec.Replicas)
        newReplicas := int(*newDeployment.Spec.Replicas)
        if oldReplicas != newReplicas {
            sendUpdates()
        }
    },
})

//factory.Start(wait.NeverStop)
//factory.WaitForCacheSync(wait.NeverStop)
informer.Run(stopper)
</code></pre>
<p>When Kubernetes autoscales or I change the Deployments replica manually, I get <code>deployment.apps/app scaled</code> but it doesn't get caught by the Informer. Nothing gets printed in the logs and it enters a crash loop with no error message.</p>
<p>I used the following resources:</p>
<ul>
<li><a href="https://dev.to/davidsbond/go-creating-dynamic-kubernetes-informers-1npi" rel="nofollow noreferrer">https://dev.to/davidsbond/go-creating-dynamic-kubernetes-informers-1npi</a></li>
<li><a href="https://stackoverflow.com/questions/53200785/whats-the-best-way-to-get-notified-when-kubernetes-deployments-change-using-the">What&#39;s the best way to get notified when kubernetes Deployments change using the k8s.io/client-go library?</a></li>
<li><a href="https://stackoverflow.com/questions/47205516/kubernetes-filter-objects-in-informer">kubernetes filter objects in Informer</a></li>
</ul>

<p>A few things to note:</p>
<ul>
<li>Before calling <code>informerFactory.Start()</code>, ensure that the Informer is called directly(<code>informer := factory.Apps().V1().Deployments().Informer()</code>) or <code>Start()</code> wont start anything.</li>
<li>Using a goroutine to start the SharedInformerFactory is meaningless because the <code>informerFactory.Start()</code> uses one internally.</li>
<li>It will also cease the <code>informerFactory.WaitForCacheSync()</code> method from working resulting in it getting the wrong data for started informers.</li>
</ul>
<pre><code>labelOptions := informers.WithTweakListOptions(func(opts *v1.ListOptions) {
    opts.FieldSelector = &quot;metadata.name=&quot; + name
})
factory := informers.NewSharedInformerFactoryWithOptions(clientSet, 2*time.Second, informers.WithNamespace(namespace), labelOptions)
informer := factory.Apps().V1().Deployments().Informer()

informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) {
        mObj, ok := obj.(*appsv1.Deployment)
        if !ok {
            doSomething()
        }
        replicas := int(*mObj.Spec.Replicas)
        doSomething() 
    },

    
    UpdateFunc: func(oldObj, newObj interface{}) {
        old, ok := oldObj.(*appsv1.Deployment)
        if !ok {
            doSomething()
        }
        newDeployment, ok := newObj.(*appsv1.Deployment)
        if !ok {
            doSomething()
        }
        oldReplicas := int(*old.Spec.Replicas)
        newReplicas := int(*newDeployment.Spec.Replicas)
        if oldReplicas != newReplicas {
            doSomething()
        }
    },
})

// Initializes all active informers and starts the internal goroutine
factory.Start(wait.NeverStop)
factory.WaitForCacheSync(wait.NeverStop)
</code></pre>
