package module
v0.4.10 Latest Latest

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

Go to latest
Published: Mar 30, 2023 License: Apache-2.0 Imports: 11 Imported by: 3


Simple Service registry based on pub/sub pattern

License Apache 2

This first version service registry use nats ( or reids ( to implement a service registry You just need to start nats before using this service registry

The project is still under development and is not ready for production.

A java implentation exist

Simple to use:

API is simple to use, simple to understand. No required external installation. No configuration file is required.

  • Connect: registry.Connect(registry.Nats(c)) init the service both on the client/server side and return registry service instance.
  • Register: reg.Register(registry.Service{Name: "httptest", URL: "http://localhost:8083/test"}) register you service on the service side.
  • GetService: reg.GetService("myservice") on the client side
  • Unregister: reg.Unregister("myservice") on the service side
  • Close : reg.Close() on the server side 'Close' function deregisters all registered services. On the client and service side, unsubsribe to subscriptions


Can be used in concurrent context. Singleton design pattern is used. The first called to registry.Connect(registry.Nats(c), registry.Timeout(100*time.MilliSecond)) create instance of registry service. And then you can get an instance of registry service without argument reg, _ := registry.Connect()


This "service registry" uses a local cache as well as the pub / sub pattern. The registration of a new service is in real time. When a new service registers, all clients are notified in real time and update their cache.


The project uses very few external dependencies. There is no service to install. Just your favorite pub/sub implementation (NATS)


Multi-tenant support is planned. The tool is based on pub / sub, each message can be pre-fixed by a text of your choice.


on the server side :

    package main

import (

	rnats ""

func main() {
	//connect to nats server
	conn, err := nats.Connect(nats.DefaultURL)
	if err != nil {
		log.Fatal("Could not connect to nats ", err)

	//create registry default instance
	reg, err := rnats.SetDefault(conn)
	if err != nil {
		log.Fatal("Could not create registry instance ", err)

	addr, _ := registry.FindFreeLocalAddress(10000, 10010)
	//register "myservice"
	fnuregister, err := reg.Register(registry.Service{Name: "myservice", Address: addr})
	if err != nil {
		log.Fatal("Could not register service ", err)

	server := http.NewServeMux()
	server.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
	if err = http.ListenAndServe(addr, server); err != nil {
		log.Fatal("could not create server ", err)



On the client side :

package main

import (

	rnats ""

func main() {
	//connect to nats server
	conn, err := nats.Connect(nats.DefaultURL)
	if err != nil {
		log.Fatal("Could not connect to nats ", err)

	//create registry default instance
	reg, err := rnats.SetDefault(conn)
	if err != nil {
		log.Fatal("Could not create registry instance ", err)

	//lookup for "myservice"
	s, err := reg.GetService("myservice")
	if err != nil {
		log.Fatal("Could not get service")

	//do something with your service
	log.Print("Find service with address ", s.Address)






This section is empty.


View Source
var (
	//DefaultTimeout timeout for GetService
	DefaultTimeout = 100 * time.Millisecond
	//DefaultRegisterInterval time between 2 registration
	DefaultRegisterInterval = 20 * time.Second
	//DefaultCheckDueInterval time between 2 checks
	DefaultCheckDueInterval = 200 * time.Millisecond
	//DefaultMainTopic default message base. All topics will start with this message
	DefaultMainTopic = "registry"
	//DefaultDueDurationFactor service expire when currentTime > lastRegisteredTime + registerInternal * dueDrationFactor
	DefaultDueDurationFactor = float32(1.5)
View Source
var (
	//ErrNotFound when no service found
	ErrNotFound = errors.New("no service found")
	//ErrNoDefaultInstance when intance singleton has not been set
	ErrNoDefaultInstance = errors.New("default instance has not been set, call SetDefault before")
View Source
var ErrNoFreePort = errors.New("no free port available")

ErrNoFreePort when no free port is available


func Close added in v0.0.8

func Close() error

Close the registry instance

Call SetDefault before

func FindFreeLocalAddress added in v0.0.7

func FindFreeLocalAddress(from, to int) (freeaddr string, err error)

FindFreeLocalAddress return local free address using range of port (

func FindFreePort added in v0.0.7

func FindFreePort(from, to int) (freeport int, err error)

FindFreePort from range of integer

func FreePort added in v0.0.7

func FreePort() (freeport int, err error)

FreePort request a new free port return -1 if error

func GetObservedServiceNames added in v0.4.5

func GetObservedServiceNames() []string

func LocalFreeAddr added in v0.0.7

func LocalFreeAddr() (freeaddr string, err error)

LocalFreeAddr return local free address (

func LocalFreeIPv6Addr added in v0.0.7

func LocalFreeIPv6Addr() (freeaddr string, err error)

LocalFreeIPv6Addr return local free address ([::1]:34545)

func Observe added in v0.0.8

func Observe(name string) error

Observe subscribe to service

Call SetDefault before use

func Port added in v0.4.5

func Port(s Service) int

Port extract port from service

func SetServiceStatus added in v0.4.3

func SetServiceStatus(s Service, status Status) error

func Unregister added in v0.0.6

func Unregister(s Service) error

Unregister unregister a service

Call SetDefault before use


type Configure added in v0.4.9

type Configure interface {
	Configure(*Options) error

type Event added in v0.0.6

type Event string

Event represent event (register|unregister|unavailbale)

const (
	//EventRegister register event
	EventRegister Event = "register"
	//EventUnregister unregister event
	EventUnregister Event = "unregister"

type Filter

type Filter func(services []*Pong) []*Pong

Filter used for filtering service do not return nil Ex Load Balancing

func LoadBalanceFilter

func LoadBalanceFilter() Filter

LoadBalanceFilter basic loadbalancer

func LocalhostFilter

func LocalhostFilter() Filter

LocalhostFilter return true if hostname is equals to service host

func PassingFilter added in v0.4.0

func PassingFilter() Filter

type FnUnregister

type FnUnregister func()

FnUnregister call this func for unregister the service

func Register added in v0.0.6

func Register(s Service) (FnUnregister, error)

Register register a new service

Call SetDefault before use

type ObserveFilter added in v0.0.6

type ObserveFilter func(s *Pong) bool

ObserveFilter used to accept (or not) new registered service.

Ex: you want only service on same host

func LocalhostOFilter added in v0.0.6

func LocalhostOFilter() ObserveFilter

LocalhostOFilter accept only service on the same machine

type ObserverEvent added in v0.0.6

type ObserverEvent func(s Service, ev Event)

ObserverEvent event tigered

type Option

type Option func(opts *Options)

Option option func

func AddFilter

func AddFilter(f Filter) Option

AddFilter add filter

func AddObserveFilter added in v0.0.6

func AddObserveFilter(f ObserveFilter) Option

AddObserveFilter adding filter

func WithLoglevel added in v0.2.0

func WithLoglevel(level logrus.Level) Option

WithLoglevel set log level

func WithMainTopic added in v0.2.0

func WithMainTopic(topic string) Option

WithMainTopic all topic will start with topic. Usefull in multi-tenancy

func WithObserverEvent added in v0.2.0

func WithObserverEvent(ev ObserverEvent) Option

WithObserverEvent set handler for Observer Event

func WithPubsub added in v0.0.6

func WithPubsub(pb pubsub.Pubsub) Option

WithPubsub initialyse service registry with nats connection

func WithRegisterInterval added in v0.2.0

func WithRegisterInterval(duration time.Duration) Option

WithRegisterInterval time between 2 register publish

func WithTimeout added in v0.2.0

func WithTimeout(timeout time.Duration) Option

WithTimeout define GetService timeout option

* GetService look service in his cache, if cache is empty, or if filtered services is empty then a ping is sent. GetService wait until a new registered service

type Options

type Options struct {
	KVOption map[string]interface{}
	// contains filtered or unexported fields

Options all configurable option

type Pong

type Pong struct {
	Timestamps *Timestamps `json:"t,omitempty"`
	Status     Status      `json:"status,omitempty"`

Pong response to ping

func (Pong) String

func (p Pong) String() string

type Registry

type Registry interface {
	Register(s Service) (FnUnregister, error)
	Unregister(s Service) error
	GetServices(name string) ([]Service, error)
	GetService(name string, filters ...Filter) (*Service, error)
	Observe(serviceName string) error
	GetObservedServiceNames() []string
	Subscribers() []string
	Close() error
	SetServiceStatus(s Service, status Status) error
	GetRegisteredServices() []Service

Registry Register, Unregister

func GetDefault added in v0.1.0

func GetDefault() (r Registry, err error)

GetDefault return default instance. return err if no default instance had been set

func NewRegistry added in v0.0.8

func NewRegistry(opts ...Option) (r Registry, err error)

NewRegistry create a new service registry instance

func SetDefault added in v0.1.0

func SetDefault(opts ...Option) (r Registry, err error)

SetDefault set the default instance

ex pubsub transport

type Service

type Service struct {
	//Network tcp/unix/tpc6
	Network string `json:"net,omitempty"`
	//Bind address
	Address string `json:"add,omitempty"`
	//URL base used for communicate with this service
	URL string `json:"url,omitempty"`
	//Name service name
	Name string `json:"name,omitempty"`
	//Version semver version
	Version string `json:"v,omitempty"`
	Host string `json:"h,omitempty"`
	//KV key value pair
	KV map[string]string `json:"kv,omitempty"`
	// contains filtered or unexported fields

Service service struct

func GetRegisteredServices added in v0.4.3

func GetRegisteredServices() ([]Service, error)

func GetService added in v0.0.8

func GetService(name string, f ...Filter) (*Service, error)

GetService find service with service name

Call SetDefault before use

func GetServices added in v0.0.8

func GetServices(name string) ([]Service, error)

GetServices return all registered service

Call SetDefault before use

func (Service) DueTime

func (s Service) DueTime() time.Time

DueTime expiration time

func (Service) String

func (s Service) String() string

type Status added in v0.4.0

type Status int
const (
	Passing Status = iota

func (*Status) FromString added in v0.4.0

func (s *Status) FromString(status string) Status

func (Status) MarshalJSON added in v0.4.0

func (s Status) MarshalJSON() ([]byte, error)

func (Status) String added in v0.4.0

func (s Status) String() string

func (*Status) UnmarshalJSON added in v0.4.0

func (s *Status) UnmarshalJSON(b []byte) error

type Timestamps

type Timestamps struct {
	//Registered date registered in nanoseconds (unix timestamp in milliseconds)
	Registered int64
	//expiration duration in milliseconds
	Duration int

Timestamps define registered datetime and expiration duration


Path Synopsis

Jump to

Keyboard shortcuts

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