Files
Jian Qiu 63d9574ca2 Add watch-based feedback with dynamic informer lifecycle management (#1350)
* Add watch-based feedback with dynamic informer lifecycle management

Implements dynamic informer registration and cleanup for resources
configured with watch-based status feedback (FeedbackScrapeType=Watch).
This enables real-time status updates for watched resources while
efficiently managing resource lifecycle.

Features:
- Automatically register informers for resources with FeedbackWatchType
- Skip informer registration for FeedbackPollType or when not configured
- Clean up informers when resources are removed from manifestwork
- Clean up informers during applied manifestwork finalization
- Clean up informers when feedback type changes from watch to poll

Implementation:
- Refactored ObjectReader to interface for better modularity
- Added UnRegisterInformerFromAppliedManifestWork helper for bulk cleanup
- Enhanced AvailableStatusController to conditionally register informers
- Updated finalization controllers to unregister informers on cleanup
- Added nil safety checks to prevent panics during cleanup

Testing:
- Unit tests for informer registration based on feedback type
- Unit tests for bulk unregistration and nil safety
- Integration test for end-to-end watch-based feedback workflow
- Integration test for informer cleanup on manifestwork deletion
- All existing tests updated and passing

This feature improves performance by using watch-based updates for
real-time status feedback while maintaining efficient resource cleanup.

Signed-off-by: Jian Qiu <jqiu@redhat.com>

* Fallback to get from client when informer is not synced

Signed-off-by: Jian Qiu <jqiu@redhat.com>

---------

Signed-off-by: Jian Qiu <jqiu@redhat.com>
2026-01-29 06:46:21 +00:00

61 lines
2.6 KiB
Go

package spoke
import (
"time"
"github.com/spf13/pflag"
"open-cluster-management.io/ocm/pkg/work/spoke/objectreader"
)
const (
defaultUserAgent = "work-agent"
)
// WorkloadAgentOptions defines the flags for workload agent
type WorkloadAgentOptions struct {
StatusSyncInterval time.Duration
AppliedManifestWorkEvictionGracePeriod time.Duration
MaxJSONRawLength int32
WorkloadSourceDriver string
WorkloadSourceConfig string
CloudEventsClientID string
CloudEventsClientCodecs []string
DefaultUserAgent string
ObjectReaderOption *objectreader.Options
}
// NewWorkloadAgentOptions returns the flags with default value set
func NewWorkloadAgentOptions() *WorkloadAgentOptions {
return &WorkloadAgentOptions{
MaxJSONRawLength: 1024,
StatusSyncInterval: 10 * time.Second,
AppliedManifestWorkEvictionGracePeriod: 60 * time.Minute,
WorkloadSourceDriver: "kube",
WorkloadSourceConfig: "/spoke/hub-kubeconfig/kubeconfig",
DefaultUserAgent: defaultUserAgent,
ObjectReaderOption: objectreader.NewOptions(),
}
}
// AddFlags register and binds the default flags
func (o *WorkloadAgentOptions) AddFlags(fs *pflag.FlagSet) {
fs.Int32Var(&o.MaxJSONRawLength, "max-json-raw-length",
o.MaxJSONRawLength, "The maximum size of the JSON raw string returned from status feedback")
fs.DurationVar(&o.StatusSyncInterval, "status-sync-interval",
o.StatusSyncInterval, "Interval to sync resource status to hub.")
fs.DurationVar(&o.AppliedManifestWorkEvictionGracePeriod, "appliedmanifestwork-eviction-grace-period",
o.AppliedManifestWorkEvictionGracePeriod, "Grace period for appliedmanifestwork eviction")
fs.StringVar(&o.WorkloadSourceDriver, "workload-source-driver",
o.WorkloadSourceDriver, "The type of workload source driver, currently it can be kube, mqtt, grpc or kafka")
fs.StringVar(&o.WorkloadSourceConfig, "workload-source-config",
o.WorkloadSourceConfig, "The config file path of current workload source")
fs.StringVar(&o.CloudEventsClientID, "cloudevents-client-id",
o.CloudEventsClientID, "The ID of the cloudevents client when workload source source is based on cloudevents")
fs.StringSliceVar(&o.CloudEventsClientCodecs, "cloudevents-client-codecs", o.CloudEventsClientCodecs,
"The codecs for cloudevents client when workload source source is based on cloudevents, the valid codecs: manifest or manifestbundle")
o.ObjectReaderOption.AddFlags(fs)
}