discovery

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 19, 2025 License: Apache-2.0 Imports: 16 Imported by: 0

README

Service Discovery Extension

Enterprise-grade service discovery and registry for distributed Forge applications.

Features

  • Multiple Backends - Consul, etcd, mDNS/Bonjour, Kubernetes, Eureka, in-memory
  • Service Registration - Automatic service registration on startup
  • Health Checks - Continuous health monitoring
  • Service Discovery - Find services by name, tags, health status
  • Load Balancing - Round-robin, random, weighted strategies
  • Service Watching - Real-time notifications of service changes
  • Auto-Deregistration - Automatic cleanup on shutdown
  • FARP Integration - Automatic API schema advertisement (OpenAPI, AsyncAPI, gRPC, GraphQL)
  • mDNS/Bonjour - Zero-config local network discovery with schema propagation

Installation

go get github.com/xraph/forge/extensions/discovery

Quick Start

Basic Usage

package main

import (
    "github.com/xraph/forge"
    "github.com/xraph/forge/extensions/discovery"
)

func main() {
    app := forge.NewApp(forge.AppConfig{
        Extensions: []forge.Extension{
            discovery.NewExtension(
                discovery.WithEnabled(true),
                discovery.WithBackend("memory"),
                discovery.WithServiceName("my-api"),
                discovery.WithServiceAddress("localhost", 8080),
                discovery.WithServiceTags("api", "v1"),
                discovery.WithHTTPHealthCheck("http://localhost:8080/_/health", 10*time.Second),
            ),
        },
    })

    // Get discovery service
    discoveryService := forge.Must[*discovery.Service](app.Container(), "discovery.Service")

    // Discover other services
    router := app.Router()
    router.GET("/call-user-service", func(ctx forge.Context) error {
        // Find a healthy user-service instance
        instance, err := discoveryService.SelectInstance(
            ctx.Context(),
            "user-service",
            discovery.LoadBalanceRoundRobin,
        )
        if err != nil {
            return err
        }

        // Make request to selected instance
        url := instance.URL("http") + "/users"
        resp, err := http.Get(url)
        // ...
    })

    app.Run()
}

Configuration

YAML Configuration

extensions:
  discovery:
    enabled: true
    backend: "consul"

    # Service configuration
    service:
      name: "my-api"
      version: "1.0.0"
      address: "10.0.1.5"
      port: 8080
      tags:
        - "api"
        - "v1"
      metadata:
        region: "us-east-1"
        environment: "production"
      enable_auto_deregister: true

    # Health check configuration
    health_check:
      enabled: true
      interval: 10s
      timeout: 5s
      deregister_critical_service_after: 1m
      http: "http://localhost:8080/_/health"

    # Watch configuration
    watch:
      enabled: true
      services:
        - "user-service"
        - "payment-service"
      tags:
        - "production"

    # Consul backend
    consul:
      address: "consul.company.com:8500"
      token: "${CONSUL_TOKEN}"
      datacenter: "dc1"
      tls_enabled: true

Programmatic Configuration

discovery.NewExtension(
    discovery.WithEnabled(true),
    discovery.WithConsul("consul.company.com:8500", os.Getenv("CONSUL_TOKEN")),
    discovery.WithService(discovery.ServiceConfig{
        Name:     "my-api",
        Version:  "1.0.0",
        Address:  "10.0.1.5",
        Port:     8080,
        Tags:     []string{"api", "v1"},
        Metadata: map[string]string{
            "region": "us-east-1",
        },
    }),
    discovery.WithHTTPHealthCheck("http://localhost:8080/_/health", 10*time.Second),
)

Usage Examples

Service Registration

// Automatic registration on app startup
// Service is automatically registered when extension starts

// Manual registration
instance := &discovery.ServiceInstance{
    ID:       "my-api-1",
    Name:     "my-api",
    Version:  "1.0.0",
    Address:  "10.0.1.5",
    Port:     8080,
    Tags:     []string{"api"},
    Metadata: map[string]string{"region": "us-east-1"},
}

err := service.Register(ctx, instance)

Service Discovery

// Discover all instances of a service
instances, err := service.Discover(ctx, "user-service")
if err != nil {
    return err
}

for _, instance := range instances {
    fmt.Printf("Found: %s at %s:%d\n", instance.ID, instance.Address, instance.Port)
}

Discover with Tags

// Discover only services with specific tags
instances, err := service.DiscoverWithTags(ctx, "user-service", []string{"production", "v2"})

Discover Healthy Services

// Discover only healthy instances
instances, err := service.DiscoverHealthy(ctx, "user-service")

Load Balancing

// Select a single instance using round-robin
instance, err := service.SelectInstance(
    ctx,
    "user-service",
    discovery.LoadBalanceRoundRobin,
)

// Get service URL
url, err := service.GetServiceURL(
    ctx,
    "user-service",
    "http",
    discovery.LoadBalanceRandom,
)

Service Watching

// Watch for service changes
err := service.Watch(ctx, "user-service", func(instances []*discovery.ServiceInstance) {
    logger.Info("user-service instances changed",
        forge.F("count", len(instances)),
    )

    // Update load balancer pool
    updatePool(instances)
})

Backends

Memory Backend (Development)

discovery.NewExtension(
    discovery.WithBackend("memory"),
)

mDNS/Bonjour Backend (Zero-Config)

NEW: Zero-configuration service discovery with automatic API schema advertisement!

discovery.NewExtension(
    discovery.WithBackend("mdns"),
    discovery.WithServiceName("my-api"),
    discovery.WithServiceAddress("", 8080), // Auto-detect address
    discovery.WithFARP(discovery.FARPConfig{
        Enabled:      true,
        AutoRegister: true,
        Endpoints: discovery.FARPEndpointsConfig{
            OpenAPI:  "/openapi.json",
            AsyncAPI: "/asyncapi.json",
        },
        Capabilities: []string{"rest", "websocket"},
    }),
)

Features:

  • ✅ Native OS support (macOS Bonjour, Linux Avahi, Windows DNS-SD)
  • ✅ Automatic API schema advertisement in TXT records
  • ✅ Zero infrastructure - works out of the box
  • ✅ Perfect for local development and IoT devices

See: FARP + mDNS Integration Guide | Quick Start

Consul Backend

discovery.NewExtension(
    discovery.WithConsul("consul.company.com:8500", os.Getenv("CONSUL_TOKEN")),
)

etcd Backend

discovery.NewExtension(
    discovery.WithEtcd([]string{
        "etcd1.company.com:2379",
        "etcd2.company.com:2379",
        "etcd3.company.com:2379",
    }),
)

Kubernetes Backend

discovery.NewExtension(
    discovery.WithKubernetes("default", true), // namespace, in-cluster
)

Eureka Backend

discovery.NewExtension(
    discovery.WithEureka([]string{
        "http://eureka1.company.com:8761/eureka",
        "http://eureka2.company.com:8761/eureka",
    }),
)

Load Balancing Strategies

Round Robin

// Distribute requests evenly across instances
instance, err := service.SelectInstance(ctx, "user-service", discovery.LoadBalanceRoundRobin)

Random

// Random selection for simple load distribution
instance, err := service.SelectInstance(ctx, "user-service", discovery.LoadBalanceRandom)

Least Connections

// Select instance with fewest active connections
instance, err := service.SelectInstance(ctx, "user-service", discovery.LoadBalanceLeastConnections)

Health Checks

HTTP Health Check

health_check:
  enabled: true
  interval: 10s
  timeout: 5s
  http: "http://localhost:8080/_/health"

TCP Health Check

health_check:
  enabled: true
  interval: 10s
  timeout: 5s
  tcp: "localhost:8080"

gRPC Health Check

health_check:
  enabled: true
  interval: 10s
  timeout: 5s
  grpc: "localhost:9090"

Service Metadata

// Register service with metadata
instance := &discovery.ServiceInstance{
    Name: "my-api",
    Metadata: map[string]string{
        "version":     "1.0.0",
        "region":      "us-east-1",
        "environment": "production",
        "datacenter":  "dc1",
    },
}

// Query metadata
if region, ok := instance.GetMetadata("region"); ok {
    fmt.Printf("Service is in region: %s\n", region)
}

Client-Side Load Balancing

// Create HTTP client with service discovery
type DiscoveryClient struct {
    service     *discovery.Service
    serviceName string
    strategy    discovery.LoadBalanceStrategy
}

func (c *DiscoveryClient) Get(ctx context.Context, path string) (*http.Response, error) {
    url, err := c.service.GetServiceURL(ctx, c.serviceName, "http", c.strategy)
    if err != nil {
        return nil, err
    }

    return http.Get(url + path)
}

// Usage
client := &DiscoveryClient{
    service:     discoveryService,
    serviceName: "user-service",
    strategy:    discovery.LoadBalanceRoundRobin,
}

resp, err := client.Get(ctx, "/users/123")

Service Tags

// Register with tags
service.Register(ctx, &discovery.ServiceInstance{
    Name: "api",
    Tags: []string{"production", "v2", "us-east"},
})

// Discover by tags
instances, err := service.DiscoverWithTags(ctx, "api", []string{"production", "v2"})

Best Practices

1. Use Health Checks

// ✅ Always enable health checks
discovery.WithHTTPHealthCheck("http://localhost:8080/_/health", 10*time.Second)

// ❌ Don't disable health checks in production

2. Include Meaningful Tags

// ✅ Good tags
Tags: []string{"production", "v2", "us-east-1", "canary"}

// ❌ Bad tags
Tags: []string{"server", "app"}

3. Auto-Deregister on Shutdown

// ✅ Always enable auto-deregister
service:
  enable_auto_deregister: true

4. Use Metadata for Configuration

// ✅ Store configuration in metadata
Metadata: map[string]string{
    "max_connections": "1000",
    "timeout": "30s",
    "protocol": "http2",
}

5. Watch Critical Services

// ✅ Watch dependencies for changes
watch:
  enabled: true
  services:
    - "database"
    - "cache"
    - "payment-gateway"

Patterns

Circuit Breaker Integration

// Combine with circuit breaker for resilience
circuitBreaker := NewCircuitBreaker(options)

instance, err := discoveryService.SelectInstance(ctx, "user-service", strategy)
if err != nil {
    return err
}

return circuitBreaker.Call(func() error {
    return callService(instance)
})

Retry with Different Instance

func callWithRetry(ctx context.Context, serviceName string, maxRetries int) error {
    for i := 0; i < maxRetries; i++ {
        instance, err := service.SelectInstance(ctx, serviceName, discovery.LoadBalanceRandom)
        if err != nil {
            return err
        }

        if err := callService(instance); err == nil {
            return nil
        }

        logger.Warn("call failed, retrying with different instance",
            forge.F("attempt", i+1),
        )
    }
    return fmt.Errorf("all retries failed")
}

Dynamic Service Pool

type ServicePool struct {
    instances []*discovery.ServiceInstance
    mu        sync.RWMutex
}

// Watch and update pool
service.Watch(ctx, "user-service", func(instances []*discovery.ServiceInstance) {
    pool.mu.Lock()
    defer pool.mu.Unlock()
    pool.instances = instances
})

Testing

func TestServiceDiscovery(t *testing.T) {
    // Use memory backend for testing
    backend := discovery.NewMemoryBackend()
    service := discovery.NewService(backend, logger)

    // Register test service
    instance := &discovery.ServiceInstance{
        ID:      "test-1",
        Name:    "test-service",
        Address: "localhost",
        Port:    8080,
        Status:  discovery.HealthStatusPassing,
    }
    service.Register(context.Background(), instance)

    // Discover
    instances, err := service.Discover(context.Background(), "test-service")
    assert.NoError(t, err)
    assert.Len(t, instances, 1)
}

Monitoring

// Expose service discovery metrics
router.GET("/_/discovery/services", func(ctx forge.Context) error {
    services, err := discoveryService.ListServices(ctx.Context())
    if err != nil {
        return err
    }

    return ctx.JSON(200, map[string]interface{}{
        "services": services,
    })
})

router.GET("/_/discovery/instances/:service", func(ctx forge.Context) error {
    serviceName := ctx.Param("service")
    instances, err := discoveryService.Discover(ctx.Context(), serviceName)
    if err != nil {
        return err
    }

    return ctx.JSON(200, map[string]interface{}{
        "service":   serviceName,
        "instances": instances,
    })
})

Performance Considerations

  • Caching: Service discovery results are cached by backends
  • Health Checks: Balance frequency vs. load (10s recommended)
  • Watch Updates: Debounce rapid changes to avoid thrashing
  • Connection Pooling: Reuse connections to backend (Consul, etcd)

Migration Guide

From Hardcoded URLs

// Before
userServiceURL := "http://user-service:8080"

// After
url, err := discoveryService.GetServiceURL(ctx, "user-service", "http", strategy)

From Environment Variables

// Before
services := map[string]string{
    "user-service": os.Getenv("USER_SERVICE_URL"),
    "payment":      os.Getenv("PAYMENT_SERVICE_URL"),
}

// After
// Services discovered automatically via service discovery

License

MIT License - see LICENSE file for details

Documentation

Index

Constants

View Source
const (
	// HealthStatusPassing indicates the service is healthy.
	HealthStatusPassing = backends.HealthStatusPassing

	// HealthStatusWarning indicates the service has warnings.
	HealthStatusWarning = backends.HealthStatusWarning

	// HealthStatusCritical indicates the service is unhealthy.
	HealthStatusCritical = backends.HealthStatusCritical

	// HealthStatusUnknown indicates the health status is unknown.
	HealthStatusUnknown = backends.HealthStatusUnknown
)

Variables

This section is empty.

Functions

func NewExtension

func NewExtension(opts ...ConfigOption) forge.Extension

NewExtension creates a new service discovery extension.

func NewExtensionWithConfig

func NewExtensionWithConfig(config Config) forge.Extension

NewExtensionWithConfig creates a new extension with complete config.

Types

type Backend

type Backend = backends.Backend

Backend defines the interface for service discovery backends.

type Config

type Config struct {
	// Enabled determines if service discovery is enabled
	Enabled bool `json:"enabled" yaml:"enabled"`

	// Backend specifies the service discovery backend
	// Options: "consul", "etcd", "kubernetes", "eureka", "memory"
	Backend string `json:"backend" yaml:"backend"`

	// Service configuration for this instance
	Service ServiceConfig `json:"service" yaml:"service"`

	// Health check settings
	HealthCheck HealthCheckConfig `json:"health_check" yaml:"health_check"`

	// Watch settings
	Watch WatchConfig `json:"watch" yaml:"watch"`

	// Consul-specific settings
	Consul ConsulConfig `json:"consul" yaml:"consul"`

	// Etcd-specific settings
	Etcd EtcdConfig `json:"etcd" yaml:"etcd"`

	// Kubernetes-specific settings
	Kubernetes KubernetesConfig `json:"kubernetes" yaml:"kubernetes"`

	// Eureka-specific settings
	Eureka EurekaConfig `json:"eureka" yaml:"eureka"`

	// MDNS-specific settings
	MDNS MDNSConfig `json:"mdns" yaml:"mdns"`

	// FARP (Forge API Gateway Registration Protocol) settings
	FARP FARPConfig `json:"farp" yaml:"farp"`
}

Config holds service discovery extension configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the default service discovery configuration.

type ConfigOption

type ConfigOption func(*Config)

ConfigOption configures the service discovery extension.

func WithAppConfig added in v0.5.0

func WithAppConfig(appConfig forge.AppConfig) ConfigOption

WithAppConfig sets the app config for auto-detecting service info This allows the extension to read Name, Version, and HTTPAddress from the app config when Service config is not fully provided.

func WithBackend

func WithBackend(backend string) ConfigOption

WithBackend sets the service discovery backend.

func WithConfig

func WithConfig(config Config) ConfigOption

WithConfig sets the complete config.

func WithConsul

func WithConsul(address, token string) ConfigOption

WithConsul configures Consul backend.

func WithEnabled

func WithEnabled(enabled bool) ConfigOption

WithEnabled sets whether service discovery is enabled.

func WithEtcd

func WithEtcd(endpoints []string) ConfigOption

WithEtcd configures etcd backend.

func WithEureka

func WithEureka(urls []string) ConfigOption

WithEureka configures Eureka backend.

func WithHTTPHealthCheck

func WithHTTPHealthCheck(endpoint string, interval time.Duration) ConfigOption

WithHTTPHealthCheck sets HTTP health check.

func WithHealthCheck

func WithHealthCheck(config HealthCheckConfig) ConfigOption

WithHealthCheck sets the health check configuration.

func WithKubernetes

func WithKubernetes(namespace string, inCluster bool) ConfigOption

WithKubernetes configures Kubernetes backend.

func WithMDNS

func WithMDNS(domain string) ConfigOption

WithMDNS configures mDNS backend.

func WithService

func WithService(service ServiceConfig) ConfigOption

WithService sets the service configuration.

func WithServiceAddress

func WithServiceAddress(address string, port int) ConfigOption

WithServiceAddress sets the service address and port.

func WithServiceMetadata

func WithServiceMetadata(metadata map[string]string) ConfigOption

WithServiceMetadata sets the service metadata.

func WithServiceName

func WithServiceName(name string) ConfigOption

WithServiceName sets the service name.

func WithServiceTags

func WithServiceTags(tags ...string) ConfigOption

WithServiceTags sets the service tags.

func WithWatch

func WithWatch(services []string, onChange func([]*ServiceInstance)) ConfigOption

WithWatch enables service watching.

type ConsulConfig

type ConsulConfig = backends.ConsulConfig

ConsulConfig holds Consul-specific configuration.

type EtcdConfig

type EtcdConfig = backends.EtcdConfig

EtcdConfig holds etcd-specific configuration.

type EurekaConfig

type EurekaConfig = backends.EurekaConfig

EurekaConfig holds Eureka-specific configuration.

type Extension

type Extension struct {
	*forge.BaseExtension
	// contains filtered or unexported fields
}

Extension implements forge.Extension for service discovery.

func (*Extension) Dependencies

func (e *Extension) Dependencies() []string

Dependencies returns extension dependencies.

func (*Extension) Health

func (e *Extension) Health(ctx context.Context) error

Health checks the extension health.

func (*Extension) Register

func (e *Extension) Register(app forge.App) error

Register registers the extension with the app.

func (*Extension) Service

func (e *Extension) Service() *Service

Service returns the service discovery service.

func (*Extension) Start

func (e *Extension) Start(ctx context.Context) error

Start starts the extension.

func (*Extension) Stop

func (e *Extension) Stop(ctx context.Context) error

Stop stops the extension gracefully.

type FARPConfig

type FARPConfig struct {
	// Enabled determines if FARP schema registration is enabled
	Enabled bool `json:"enabled" yaml:"enabled"`

	// AutoRegister automatically registers schemas on service startup
	AutoRegister bool `json:"auto_register" yaml:"auto_register"`

	// Strategy for schema storage: "push" (to registry), "pull" (HTTP only), "hybrid"
	Strategy string `json:"strategy" yaml:"strategy"`

	// Schemas to register
	Schemas []FARPSchemaConfig `json:"schemas" yaml:"schemas"`

	// Endpoints configuration
	Endpoints FARPEndpointsConfig `json:"endpoints" yaml:"endpoints"`

	// Capabilities advertised by this service
	Capabilities []string `json:"capabilities" yaml:"capabilities"`
}

FARPConfig holds FARP (Forge API Gateway Registration Protocol) configuration.

type FARPEndpointsConfig

type FARPEndpointsConfig struct {
	// Health check endpoint
	Health string `json:"health" yaml:"health"`

	// Metrics endpoint
	Metrics string `json:"metrics,omitempty" yaml:"metrics,omitempty"`

	// OpenAPI spec endpoint
	OpenAPI string `json:"openapi,omitempty" yaml:"openapi,omitempty"`

	// AsyncAPI spec endpoint
	AsyncAPI string `json:"asyncapi,omitempty" yaml:"asyncapi,omitempty"`

	// gRPC reflection enabled
	GRPCReflection bool `json:"grpc_reflection,omitempty" yaml:"grpc_reflection,omitempty"`

	// GraphQL endpoint
	GraphQL string `json:"graphql,omitempty" yaml:"graphql,omitempty"`
}

FARPEndpointsConfig configures service endpoints.

type FARPLocationConfig

type FARPLocationConfig struct {
	// Type: "http", "registry", "inline"
	Type string `json:"type" yaml:"type"`

	// URL for HTTP location type
	URL string `json:"url,omitempty" yaml:"url,omitempty"`

	// RegistryPath for registry location type
	RegistryPath string `json:"registry_path,omitempty" yaml:"registry_path,omitempty"`

	// Headers for HTTP authentication
	Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
}

FARPLocationConfig configures where the schema is located.

type FARPSchemaConfig

type FARPSchemaConfig struct {
	// Type of schema: "openapi", "asyncapi", "grpc", "graphql"
	Type string `json:"type" yaml:"type"`

	// SpecVersion is the schema specification version (e.g., "3.1.0" for OpenAPI)
	SpecVersion string `json:"spec_version" yaml:"spec_version"`

	// Location configuration
	Location FARPLocationConfig `json:"location" yaml:"location"`

	// ContentType is the schema content type
	ContentType string `json:"content_type" yaml:"content_type"`
}

FARPSchemaConfig configures a single schema to register.

type HealthCheckConfig

type HealthCheckConfig struct {
	// Enabled determines if health checks are enabled
	Enabled bool `json:"enabled" yaml:"enabled"`

	// Interval is how often to perform health checks
	Interval time.Duration `json:"interval" yaml:"interval"`

	// Timeout is the health check timeout
	Timeout time.Duration `json:"timeout" yaml:"timeout"`

	// DeregisterCriticalServiceAfter is when to deregister unhealthy services
	DeregisterCriticalServiceAfter time.Duration `json:"deregister_critical_service_after" yaml:"deregister_critical_service_after"`

	// HTTP health check endpoint (if using HTTP)
	HTTP string `json:"http" yaml:"http"`

	// TCP health check address (if using TCP)
	TCP string `json:"tcp" yaml:"tcp"`

	// gRPC health check address (if using gRPC)
	GRPC string `json:"grpc" yaml:"grpc"`
}

HealthCheckConfig holds health check configuration.

type HealthStatus

type HealthStatus = backends.HealthStatus

HealthStatus represents service health status.

type KubernetesConfig

type KubernetesConfig = backends.KubernetesConfig

KubernetesConfig holds Kubernetes-specific configuration.

type LoadBalanceStrategy

type LoadBalanceStrategy string

LoadBalanceStrategy defines load balancing strategies.

const (
	// LoadBalanceRoundRobin uses round-robin selection.
	LoadBalanceRoundRobin LoadBalanceStrategy = "round_robin"

	// LoadBalanceRandom uses random selection.
	LoadBalanceRandom LoadBalanceStrategy = "random"

	// LoadBalanceLeastConnections uses least connections selection.
	LoadBalanceLeastConnections LoadBalanceStrategy = "least_connections"

	// LoadBalanceWeightedRoundRobin uses weighted round-robin.
	LoadBalanceWeightedRoundRobin LoadBalanceStrategy = "weighted_round_robin"
)

type MDNSConfig

type MDNSConfig = backends.MDNSConfig

MDNSConfig holds mDNS/DNS-SD-specific configuration Works natively on macOS (Bonjour), Linux (Avahi), and Windows (DNS-SD).

type SchemaPublisher

type SchemaPublisher struct {
	// contains filtered or unexported fields
}

SchemaPublisher handles FARP schema registration.

func NewSchemaPublisher

func NewSchemaPublisher(config FARPConfig, app forge.App) *SchemaPublisher

NewSchemaPublisher creates a new schema publisher.

func (*SchemaPublisher) Close

func (p *SchemaPublisher) Close() error

Close closes the schema publisher.

func (*SchemaPublisher) GetManifest

func (p *SchemaPublisher) GetManifest(ctx context.Context, instanceID string) (*farp.SchemaManifest, error)

GetManifest retrieves the manifest for an instance.

func (*SchemaPublisher) GetMetadataForDiscovery added in v0.5.0

func (p *SchemaPublisher) GetMetadataForDiscovery(baseURL string) map[string]string

GetMetadataForDiscovery returns metadata that should be added to service discovery This allows mDNS/Bonjour and other backends to advertise FARP endpoints in TXT records.

func (*SchemaPublisher) Publish

func (p *SchemaPublisher) Publish(ctx context.Context, instanceID string) error

Publish generates and publishes schemas for the service.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides high-level service discovery operations.

func NewService

func NewService(backend Backend, logger forge.Logger) *Service

NewService creates a new service discovery service.

func (*Service) Deregister

func (s *Service) Deregister(ctx context.Context, serviceID string) error

Deregister deregisters a service instance.

func (*Service) Discover

func (s *Service) Discover(ctx context.Context, serviceName string) ([]*ServiceInstance, error)

Discover discovers service instances by name.

func (*Service) DiscoverHealthy

func (s *Service) DiscoverHealthy(ctx context.Context, serviceName string) ([]*ServiceInstance, error)

DiscoverHealthy discovers only healthy service instances.

func (*Service) DiscoverWithTags

func (s *Service) DiscoverWithTags(ctx context.Context, serviceName string, tags []string) ([]*ServiceInstance, error)

DiscoverWithTags discovers service instances by name and tags.

func (*Service) GetServiceURL

func (s *Service) GetServiceURL(ctx context.Context, serviceName string, scheme string, strategy LoadBalanceStrategy) (string, error)

GetServiceURL gets a service URL using load balancing.

func (*Service) Health

func (s *Service) Health(ctx context.Context) error

Health checks backend health.

func (*Service) ListServices

func (s *Service) ListServices(ctx context.Context) ([]string, error)

ListServices lists all registered services.

func (*Service) Register

func (s *Service) Register(ctx context.Context, instance *ServiceInstance) error

Register registers a service instance.

func (*Service) SelectInstance

func (s *Service) SelectInstance(ctx context.Context, serviceName string, strategy LoadBalanceStrategy) (*ServiceInstance, error)

SelectInstance selects a single service instance using load balancing strategy.

func (*Service) Watch

func (s *Service) Watch(ctx context.Context, serviceName string, onChange func([]*ServiceInstance)) error

Watch watches for changes to a service.

type ServiceConfig

type ServiceConfig struct {
	// Name is the service name
	Name string `json:"name" yaml:"name"`

	// ID is the unique service instance ID (auto-generated if empty)
	ID string `json:"id" yaml:"id"`

	// Version is the service version
	Version string `json:"version" yaml:"version"`

	// Address is the service address
	Address string `json:"address" yaml:"address"`

	// Port is the service port
	Port int `json:"port" yaml:"port"`

	// Tags are service tags for filtering
	Tags []string `json:"tags" yaml:"tags"`

	// Metadata is arbitrary service metadata
	Metadata map[string]string `json:"metadata" yaml:"metadata"`

	// EnableAutoDeregister enables automatic deregistration on shutdown
	EnableAutoDeregister bool `json:"enable_auto_deregister" yaml:"enable_auto_deregister"`
}

ServiceConfig holds service registration configuration.

type ServiceEvent

type ServiceEvent struct {
	// Type is the event type
	Type ServiceEventType

	// Service is the service instance
	Service *ServiceInstance

	// Timestamp is when the event occurred
	Timestamp int64
}

ServiceEvent represents a service change event.

type ServiceEventType

type ServiceEventType string

ServiceEventType represents types of service events.

const (
	// ServiceEventRegistered indicates a service was registered.
	ServiceEventRegistered ServiceEventType = "registered"

	// ServiceEventDeregistered indicates a service was deregistered.
	ServiceEventDeregistered ServiceEventType = "deregistered"

	// ServiceEventHealthChanged indicates service health changed.
	ServiceEventHealthChanged ServiceEventType = "health_changed"

	// ServiceEventMetadataChanged indicates service metadata changed.
	ServiceEventMetadataChanged ServiceEventType = "metadata_changed"
)

type ServiceInstance

type ServiceInstance = backends.ServiceInstance

ServiceInstance represents a registered service instance.

type ServiceQuery

type ServiceQuery struct {
	// Name is the service name to query
	Name string

	// Tags are tags to filter by
	Tags []string

	// OnlyHealthy returns only healthy instances
	OnlyHealthy bool

	// LoadBalanceStrategy is the load balancing strategy
	LoadBalanceStrategy LoadBalanceStrategy
}

ServiceQuery represents a service discovery query.

type ServiceRegistration

type ServiceRegistration struct {
	// Service is the service configuration
	Service ServiceConfig

	// HealthCheck is the health check configuration
	HealthCheck HealthCheckConfig
}

ServiceRegistration represents a service registration request.

type WatchConfig

type WatchConfig struct {
	// Enabled determines if service watching is enabled
	Enabled bool `json:"enabled" yaml:"enabled"`

	// Services are service names to watch for changes
	Services []string `json:"services" yaml:"services"`

	// Tags are tags to filter services
	Tags []string `json:"tags" yaml:"tags"`

	// OnChange is called when watched services change
	// This is set programmatically, not via config
	OnChange func(services []*ServiceInstance)
}

WatchConfig holds service watch configuration.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL