Skip to content

feat(registry): add Custom Discoverer interface (#767)#4130

Open
btlqql wants to merge 1 commit into
higress-group:mainfrom
btlqql:btlqql/issue-767
Open

feat(registry): add Custom Discoverer interface (#767)#4130
btlqql wants to merge 1 commit into
higress-group:mainfrom
btlqql:btlqql/issue-767

Conversation

@btlqql

@btlqql btlqql commented Jul 12, 2026

Copy link
Copy Markdown

What this PR does

Resolves #767 by adding a standard Custom Discoverer interface so users can plug custom registration centers (e.g. xDS or HTTP watch based) into Higress through the existing service-discovery pipeline, instead of adding a dedicated watcher package for every new registry type.

The interface mirrors the Prometheus discovery.Discoverer contract requested in the issue:

type Discoverer interface {
    Run(ctx context.Context, up chan<- []*TargetGroup)
}

type TargetGroup struct {
    Targets []LabelSet // each carries "__instance__" (host:port) + optional labels (protocol, hostname, ...)
    Labels  LabelSet   // shared labels; "job"/"__service__" names the service
    Source  string
}

A discoverer reports the full current snapshot of target groups on every update (not a delta), exactly like Prometheus discoverers.

How it is wired

  • registry.RegisterDiscoverer(type, factory) registers a DiscovererFactory under a registry type (standard Go factory pattern, like database/sql.Register). The factory receives the full McpBridge RegistryConfig plus the resolved AuthOption, so custom discoverers can reuse existing fields such as Domain, Port, Protocol and Metadata.
  • Reconciler.generateWatcherFromRegistryConfig now falls back to a registered discoverer for any registry type that is not one of the built-in ones (nacos/nacos2/nacos3/zookeeper/consul/static/dns/eureka). An adapter watcher (registry/custom) runs the discoverer and converts every snapshot into ingress.ServiceWrapper entries in the shared memory cache, reconciling additions and removals on each update and cleaning up on Stop() — identical lifecycle to the built-in watchers.
  • No new API/CRD fields are required: a custom discoverer is selected purely by the existing RegistryConfig.type.

Why native types instead of github.com/prometheus/prometheus

The issue's example uses Prometheus' targetgroup.Group / model.LabelSet. Those modules are already indirect dependencies, but promoting the very large prometheus/prometheus module to a direct dependency of the core registry package would add significant weight and version risk for no semantic gain. The introduced TargetGroup/LabelSet types mirror the Prometheus structure and semantics exactly, keeping the registry package self-contained.

Relationship to MCP

As discussed in the issue, MCP-based discovery remains supported and is complementary: an MCP-over-xDS discoverer can be registered through this same interface. This change reuses the existing Reconciler/Cache/push pipeline rather than introducing a new push mechanism.

Changes

  • registry/discoverer.goDiscoverer interface, TargetGroup/LabelSet types, label constants, and the RegisterDiscoverer/LookupDiscovererFactory factory registry.
  • registry/custom/watcher.go — adapter that bridges a Discoverer to the Watcher interface, including the TargetGroupServiceEntry/ServiceWrapper conversion (host:port + protocol parsing, IPv4/IPv6, default-HTTP fallback, snapshot reconciliation).
  • registry/reconcile/reconcile.go — dispatch unknown registry types to a registered discoverer factory.
  • registry/discoverer_test.go, registry/custom/watcher_test.go — unit tests for registration (duplicate/invalid panics, lookup), conversion edge cases (invalid instances, service-name resolution, IPv6, protocol fallback) and the adapter lifecycle (add/update/remove/stop) including -race.

Verification

  • go build ./registry/... ./pkg/ingress/config/... ./pkg/bootstrap/... — passes (downstream consumers of the reconciler build cleanly).
  • go test ./registry/ ./registry/custom/ — passes, including go test -race -count=3.
  • go vet ./registry ./registry/custom ./registry/reconcile — clean.
  • gofmt — clean for all added/changed files.
  • go.mod/go.sum — unchanged (no new dependencies introduced).

Pre-existing failures in registry/nacos and registry/nacos/v2 (Test_generateServiceEntry_Weight, Test_generateServiceEntry_WeightFieldSet) are unrelated to this change and reproduce on the unmodified base commit.

Notes / assumptions

  • Custom discoverers register under an arbitrary type string (a conventional custom type constant is also exported). They are responsible for providing unique service host names via the job/__service__ group label or Source, since the cache is keyed by host.
  • No documentation files were added per repository conventions; this PR description documents the public API.

Resolve higress-group#767.
Add a standard Discoverer interface so users can plug custom registration
centers (e.g. xDS or HTTP watch based) into Higress through the existing
Reconciler/Cache pipeline, instead of having to add a dedicated watcher
package per registry type.
The interface mirrors the Prometheus discovery.Discoverer contract:
    type Discoverer interface {
        Run(ctx context.Context, up chan<- []*TargetGroup)
    }
A TargetGroup carries a list of labeled targets (the "__instance__" label
holds "host:port", optional labels include "protocol" and "hostname") and
shared group labels (the "job"/"__service__" label names the service).
Implementations are registered by registry type via RegisterDiscoverer (the
standard Go factory-registration pattern, like database/sql.Register) and
built from the full McpBridge RegistryConfig, so they can reuse fields such
as Domain, Port, Protocol and Metadata. The reconciler now falls back to a
registered discoverer for any registry type that is not one of the built-in
ones (nacos/zookeeper/consul/eureka/static/dns); an adapter watcher converts
every discovery snapshot into ingress.ServiceWrapper entries stored in the
shared memory cache, reconciling additions and removals on each update.
Native TargetGroup/LabelSet types are used instead of importing
github.com/prometheus/prometheus so the core registry package does not pull
in the heavyweight Prometheus module as a direct dependency; the structure
and semantics match Prometheus' targetgroup.Group/model.LabelSet exactly.
This reuses the existing service-discovery pipeline (no new push mechanism)
and is complementary to MCP-based discovery: an MCP-over-xDS discoverer can
be registered the same way, as mentioned in the issue discussion.

Signed-off-by: btlqql <2977859784@qq.com>
@CLAassistant

CLAassistant commented Jul 12, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Custom Discoverer interface

2 participants