circleyu opened a new issue, #2849:
URL: https://github.com/apache/apisix-ingress-controller/issues/2849

   ## Description
   
   Deleting an `ApisixConsumer` is processed correctly by the provider (the 
consumer is removed from APISIX), but `ApisixConsumerReconciler` still returns 
the original `NotFound` error. controller-runtime then rate-limits and retries 
the same request indefinitely, flooding the logs with:
   
   ```text
   ERROR  controllers.ApisixConsumer  failed to get ApisixConsumer  {"error": 
"ApisixConsumer.apisix.apache.org \"<name>\" not found"}
   ERROR  controller-runtime          Reconciler error
   INFO   provider.client             syncing all resources
   ```
   
   This is still present on `master`:
   
   
https://github.com/apache/apisix-ingress-controller/blob/master/internal/controller/apisixconsumer_controller.go
   
   ## Steps to reproduce
   
   1. Create a namespaced `ApisixConsumer` that AIC watches (any namespace the 
controller is configured for), for example key-auth with a `secretRef`.
   2. Wait until it is accepted / synced (`service_number` increases, ingest 
with the key succeeds).
   3. Delete the CR:
   
      ```bash
      kubectl -n <ns> delete apisixconsumer <name>
      ```
   
   4. Watch AIC logs.
   
   ## Expected
   
   After `Get` returns `NotFound` and `Provider.Delete` succeeds, reconcile 
should return `ctrl.Result{}, nil` and stop. No further retries for that object.
   
   This is already how `ApisixTlsReconciler` behaves:
   
   ```go
   if err := r.Get(ctx, req.NamespacedName, &tls); err != nil {
       if client.IgnoreNotFound(err) == nil {
           // ...
           if err := r.Provider.Delete(ctx, &tls); err != nil {
               return ctrl.Result{}, err
           }
           r.Log.Info("deleted apisix tls", "tls", tls.Name)
           return ctrl.Result{}, nil
       }
       return ctrl.Result{}, err
   }
   ```
   
   
https://github.com/apache/apisix-ingress-controller/blob/master/internal/controller/apisixtls_controller.go
   
   ## Actual
   
   `ApisixConsumerReconciler.Reconcile` (current `master`):
   
   ```go
   ac := &apiv2.ApisixConsumer{}
   if err := r.Get(ctx, req.NamespacedName, ac); err != nil {
       if k8serrors.IsNotFound(err) {
           ac.Namespace = req.Namespace
           ac.Name = req.Name
           ac.TypeMeta = metav1.TypeMeta{
               Kind:       KindApisixConsumer,
               APIVersion: apiv2.GroupVersion.String(),
           }
           if err := r.Provider.Delete(ctx, ac); err != nil {
               r.Log.Error(err, "failed to delete provider", "ApisixConsumer", 
utils.NamespacedName(ac))
               return ctrl.Result{}, err
           }
           // missing: return ctrl.Result{}, nil
       }
       r.Log.Error(err, "failed to get ApisixConsumer", "request", 
req.NamespacedName)
       return ctrl.Result{}, err
   }
   ```
   
   When `Get` is `NotFound` and `Provider.Delete` succeeds, execution falls 
through and still returns the `NotFound` error. controller-runtime treats that 
as a failed reconcile and retries with exponential backoff (observed ~20s, 
~41s, then continuing until max delay).
   
   The provider path itself appears fine: each retry is followed by `syncing 
all resources`, so the delete is applied (and then re-applied). The object is 
gone from the API server.
   
   ## Sample logs
   
   ```text
   INFO   controllers.ApisixConsumer  reconcile
          {"request": 
{"name":"cust-8fa274728c24","namespace":"signalgate-consumers"}}
   ERROR  controllers.ApisixConsumer  failed to get ApisixConsumer
          {"request": 
{"name":"cust-8fa274728c24","namespace":"signalgate-consumers"},
           "error": "ApisixConsumer.apisix.apache.org \"cust-8fa274728c24\" not 
found"}
   ERROR  controller-runtime          Reconciler error
          {"controller": "apisixconsumer", "controllerKind": "ApisixConsumer",
           "namespace": "signalgate-consumers", "name": "cust-8fa274728c24",
           "error": "ApisixConsumer.apisix.apache.org \"cust-8fa274728c24\" not 
found"}
   INFO   provider.client             syncing all resources
   INFO   provider.client             syncing resources for config  
{"service_number": 27}
   ```
   
   Line numbers in a 2.x build match 
`controller/apisixconsumer_controller.go:61` (reconcile) and `:77` (`failed to 
get ApisixConsumer`).
   
   Restarting the AIC pod clears the workqueue and stops the loop until the 
next delete.
   
   ## Suggested fix
   
   Return success after a successful provider delete on `NotFound`, and only 
log/return `Get` errors that are not `NotFound`:
   
   ```go
   if err := r.Get(ctx, req.NamespacedName, ac); err != nil {
       if k8serrors.IsNotFound(err) {
           ac.Namespace = req.Namespace
           ac.Name = req.Name
           ac.TypeMeta = metav1.TypeMeta{
               Kind:       KindApisixConsumer,
               APIVersion: apiv2.GroupVersion.String(),
           }
           if err := r.Provider.Delete(ctx, ac); err != nil {
               r.Log.Error(err, "failed to delete provider", "ApisixConsumer", 
utils.NamespacedName(ac))
               return ctrl.Result{}, err
           }
           return ctrl.Result{}, nil
       }
       r.Log.Error(err, "failed to get ApisixConsumer", "request", 
req.NamespacedName)
       return ctrl.Result{}, err
   }
   ```
   
   Please also check other 2.x reconcilers for the same fall-through. 
`ApisixTlsReconciler` already returns `nil` after delete; `ApisixConsumer` does 
not.
   
   ## Environment
   
   - APISIX Ingress Controller: 2.x (controller-runtime `ApisixConsumer` 
reconciler; `controller/apisixconsumer_controller.go`)
   - Trigger: `kubectl delete` of `ApisixConsumer` (or any client that deletes 
the CR)
   - Confirmed against current `master` source


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to