func (gr *Reconciler) finalizeUsing(h Handler, resource runtime.Object, crname string, aggregated []reconciler.Object) error {
	cname := crname + "(using:" + reflect.TypeOf(h).String() + ")"
	log.Printf("%s  { finalizing\n", cname)
	defer log.Printf("%s  } finalizing\n", cname)
	expected, observed, dependent, stage, err := gr.observeAndMutate(h, resource, crname, aggregated)
	if err != nil {
		handleError(stage, crname, err)
	}
	aggregated = append(aggregated, expected...)
	stage = "finalizing resource"
	err = finalize(h, resource, observed, dependent)
	if err == nil {
		stage = "finalizing deletion of objects"
		for _, o := range observed {
			oRsrcName := o.Obj.GetName()
			if o.Delete {
				if rm, e := gr.itemMgr(o); e != nil {
					err = e
					break
				} else if e := rm.Delete(o); e != nil {
					err = e
					break
				} else {
					log.Printf("%s   -delete: %s\n", cname, oRsrcName)
				}
			}
		}
	}
	if err != nil {
		handleError(stage, crname, err)
	}
	return err
}
finalizeUsing is a function that finalizes component
package genericreconciler
import (
	"context"
	"fmt"
	apierror "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	urt "k8s.io/apimachinery/pkg/util/runtime"
	"log"
	"reflect"
	"sigs.k8s.io/controller-reconciler/pkg/reconciler"
	rmanager "sigs.k8s.io/controller-reconciler/pkg/reconciler/manager"
	"sigs.k8s.io/controller-reconciler/pkg/reconciler/manager/k8s"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"time"
)
const (
	DefaultReconcilePeriod      = 3 * time.Minute
	FinalizeReconcilePeriod     = 30 * time.Second
	CRGetFailureReconcilePeriod = 30 * time.Second
)
func handleErrorArr(info string, name string, e error, errs []error) []error {
	handleError(info, name, e)
	return append(errs, e)
}
func handleError(info string, name string, e error) error {
	urt.HandleError(fmt.Errorf("Failed: [%s] %s. %s", name, info, e.Error()))
	return e
}
func (gr *Reconciler) itemMgr(i reconciler.Object) (rmanager.Manager, error) {
	m := gr.rsrcMgr.Get(i.Type)
	if m == nil {
		return m, fmt.Errorf("Resource Manager not registered for Type: %s", i.Type)
	}
	return m, nil
}
func (gr *Reconciler) ReconcileResource(namespacedname types.NamespacedName) (reconcile.Result, error) {
	var p time.Duration
	period := DefaultReconcilePeriod
	expected := []reconciler.Object{}
	resource := gr.resource.(runtime.Object).DeepCopyObject()
	nname := reflect.TypeOf(resource).String() + "/" + namespacedname.String()
	rm := gr.rsrcMgr.Get("k8s")
	err := k8s.Get(rm, namespacedname, resource.(runtime.Object))
	if err != nil {
		if apierror.IsNotFound(err) {
			urt.HandleError(fmt.Errorf("not found %s. %s", nname, err.Error()))
			return reconcile.Result{}, nil
		}
		return reconcile.Result{RequeueAfter: CRGetFailureReconcilePeriod}, err
	}
	errkind := ""
	if gr.validate != nil {
		log.Printf("%s Validating spec\n", nname)
		err = gr.validate(resource)
	}
	if err == nil {
		if gr.applyDefaults != nil {
			log.Printf("%s Applying defaults\n", nname)
			gr.applyDefaults(resource)
		}
		o := resource.(metav1.Object)
		for _, h := range gr.using {
			if o.GetDeletionTimestamp() == nil {
				p, err = gr.reconcileUsing(h, resource, nname, expected)
			} else {
				err = gr.finalizeUsing(h, resource, nname, expected)
				p = FinalizeReconcilePeriod
			}
			if p != 0 && p < period {
				period = p
			}
			if err != nil {
				break
			}
		}
	} else {
		errkind = "validate"
	}
	if err != nil {
		urt.HandleError(fmt.Errorf("error reconciling %s. %s", nname, err.Error()))
		if gr.errorHandler != nil {
			gr.errorHandler(resource, err, errkind)
		}
	}
	err = rm.Update(reconciler.Object{Obj: &k8s.Object{Obj: resource.(metav1.Object)}})
	if err != nil {
		urt.HandleError(fmt.Errorf("error updating %s. %s", nname, err.Error()))
	}
	return reconcile.Result{RequeueAfter: period}, err
}
func (gr *Reconciler) observe(observables []reconciler.Observable) ([]reconciler.Object, error) {
	seen := []reconciler.Object{}
	for _, m := range gr.rsrcMgr.All() {
		o, err := m.Observe(observables...)
		if err != nil {
			return []reconciler.Object{}, err
		}
		seen = append(seen, o...)
	}
	return seen, nil
}
func (gr *Reconciler) observeAndMutate(h Handler, resource runtime.Object, crname string, aggregated []reconciler.Object) ([]reconciler.Object, []reconciler.Object, []reconciler.Object, string, error) {
	var err error
	var expected, observed, dependent []reconciler.Object
	stage := "dependent resources"
	labels := getLabels(resource, reflect.TypeOf(h).String())
	dependent, err = gr.observe(getAllObservables(&gr.rsrcMgr, dependentResources(h, resource), labels))
	if err == nil && dependent != nil {
		stage = "observing resources"
		observed, err = gr.observe(h.Observables(resource, labels, dependent))
		if err == nil && observed != nil {
			stage = "gathering expected resources"
			expected, err = h.Objects(resource, labels, observed, dependent, aggregated)
		}
	}
	if err != nil {
		observed = []reconciler.Object{}
		expected = []reconciler.Object{}
	}
	if expected == nil {
		expected = []reconciler.Object{}
	}
	if observed == nil {
		observed = []reconciler.Object{}
	}
	return expected, observed, dependent, stage, err
}