updates #207
| @@ -46,6 +46,12 @@ type Broker interface { | |||||||
| 	BatchSubscribe(ctx context.Context, topic string, h BatchHandler, opts ...SubscribeOption) (Subscriber, error) | 	BatchSubscribe(ctx context.Context, topic string, h BatchHandler, opts ...SubscribeOption) (Subscriber, error) | ||||||
| 	// String type of broker | 	// String type of broker | ||||||
| 	String() string | 	String() string | ||||||
|  | 	// Live returns broker liveness | ||||||
|  | 	Live() bool | ||||||
|  | 	// Ready returns broker readiness | ||||||
|  | 	Ready() bool | ||||||
|  | 	// Health returns broker health | ||||||
|  | 	Health() bool | ||||||
| } | } | ||||||
|  |  | ||||||
| type ( | type ( | ||||||
|   | |||||||
| @@ -339,6 +339,18 @@ func (m *memoryBroker) Name() string { | |||||||
| 	return m.opts.Name | 	return m.opts.Name | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (m *memoryBroker) Live() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *memoryBroker) Ready() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *memoryBroker) Health() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| func (m *memoryEvent) Topic() string { | func (m *memoryEvent) Topic() string { | ||||||
| 	return m.topic | 	return m.topic | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,6 +25,18 @@ func NewBroker(opts ...Option) *NoopBroker { | |||||||
| 	return b | 	return b | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (b *NoopBroker) Health() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *NoopBroker) Live() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *NoopBroker) Ready() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| func (b *NoopBroker) Name() string { | func (b *NoopBroker) Name() string { | ||||||
| 	return b.opts.Name | 	return b.opts.Name | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ import ( | |||||||
| 	"go.unistack.org/micro/v3/logger" | 	"go.unistack.org/micro/v3/logger" | ||||||
| 	"go.unistack.org/micro/v3/metadata" | 	"go.unistack.org/micro/v3/metadata" | ||||||
| 	"go.unistack.org/micro/v3/meter" | 	"go.unistack.org/micro/v3/meter" | ||||||
| 	"go.unistack.org/micro/v3/network/transport" |  | ||||||
| 	"go.unistack.org/micro/v3/options" | 	"go.unistack.org/micro/v3/options" | ||||||
| 	"go.unistack.org/micro/v3/register" | 	"go.unistack.org/micro/v3/register" | ||||||
| 	"go.unistack.org/micro/v3/router" | 	"go.unistack.org/micro/v3/router" | ||||||
| @@ -22,8 +21,6 @@ import ( | |||||||
|  |  | ||||||
| // Options holds client options | // Options holds client options | ||||||
| type Options struct { | type Options struct { | ||||||
| 	// Transport used for transfer messages |  | ||||||
| 	Transport transport.Transport |  | ||||||
| 	// Selector used to select needed address | 	// Selector used to select needed address | ||||||
| 	Selector selector.Selector | 	Selector selector.Selector | ||||||
| 	// Logger used to log messages | 	// Logger used to log messages | ||||||
| @@ -194,18 +191,16 @@ func NewOptions(opts ...Option) Options { | |||||||
| 			Retry:          DefaultRetry, | 			Retry:          DefaultRetry, | ||||||
| 			Retries:        DefaultRetries, | 			Retries:        DefaultRetries, | ||||||
| 			RequestTimeout: DefaultRequestTimeout, | 			RequestTimeout: DefaultRequestTimeout, | ||||||
| 			DialTimeout:    transport.DefaultDialTimeout, |  | ||||||
| 		}, | 		}, | ||||||
| 		Lookup:    LookupRoute, | 		Lookup:   LookupRoute, | ||||||
| 		PoolSize:  DefaultPoolSize, | 		PoolSize: DefaultPoolSize, | ||||||
| 		PoolTTL:   DefaultPoolTTL, | 		PoolTTL:  DefaultPoolTTL, | ||||||
| 		Selector:  random.NewSelector(), | 		Selector: random.NewSelector(), | ||||||
| 		Logger:    logger.DefaultLogger, | 		Logger:   logger.DefaultLogger, | ||||||
| 		Broker:    broker.DefaultBroker, | 		Broker:   broker.DefaultBroker, | ||||||
| 		Meter:     meter.DefaultMeter, | 		Meter:    meter.DefaultMeter, | ||||||
| 		Tracer:    tracer.DefaultTracer, | 		Tracer:   tracer.DefaultTracer, | ||||||
| 		Router:    router.DefaultRouter, | 		Router:   router.DefaultRouter, | ||||||
| 		Transport: transport.DefaultTransport, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| @@ -278,13 +273,6 @@ func PoolTTL(d time.Duration) Option { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // Transport to use for communication e.g http, rabbitmq, etc |  | ||||||
| func Transport(t transport.Transport) Option { |  | ||||||
| 	return func(o *Options) { |  | ||||||
| 		o.Transport = t |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Register sets the routers register | // Register sets the routers register | ||||||
| func Register(r register.Register) Option { | func Register(r register.Register) Option { | ||||||
| 	return func(o *Options) { | 	return func(o *Options) { | ||||||
| @@ -334,14 +322,6 @@ func TLSConfig(t *tls.Config) Option { | |||||||
| 	return func(o *Options) { | 	return func(o *Options) { | ||||||
| 		// set the internal tls | 		// set the internal tls | ||||||
| 		o.TLSConfig = t | 		o.TLSConfig = t | ||||||
|  |  | ||||||
| 		// set the default transport if one is not |  | ||||||
| 		// already set. Required for Init call below. |  | ||||||
|  |  | ||||||
| 		// set the transport tls |  | ||||||
| 		_ = o.Transport.Init( |  | ||||||
| 			transport.TLSConfig(t), |  | ||||||
| 		) |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -507,13 +487,6 @@ func WithAuthToken(t string) CallOption { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // WithNetwork is a CallOption which sets the network attribute |  | ||||||
| func WithNetwork(n string) CallOption { |  | ||||||
| 	return func(o *CallOptions) { |  | ||||||
| 		o.Network = n |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // WithRouter sets the router to use for this call | // WithRouter sets the router to use for this call | ||||||
| func WithRouter(r router.Router) CallOption { | func WithRouter(r router.Router) CallOption { | ||||||
| 	return func(o *CallOptions) { | 	return func(o *CallOptions) { | ||||||
|   | |||||||
| @@ -38,4 +38,10 @@ type Cluster interface { | |||||||
| 	Broadcast(ctx context.Context, msg Message, filter ...string) error | 	Broadcast(ctx context.Context, msg Message, filter ...string) error | ||||||
| 	// Unicast send message to single member in cluster | 	// Unicast send message to single member in cluster | ||||||
| 	Unicast(ctx context.Context, node Node, msg Message) error | 	Unicast(ctx context.Context, node Node, msg Message) error | ||||||
|  | 	// Live returns cluster liveness | ||||||
|  | 	Live() bool | ||||||
|  | 	// Ready returns cluster readiness | ||||||
|  | 	Ready() bool | ||||||
|  | 	// Health returns cluster health | ||||||
|  | 	Health() bool | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ package config | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" |  | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| @@ -139,7 +138,7 @@ var ( | |||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
| 			if err := fn(ctx, c); err != nil { | 			if err := fn(ctx, c); err != nil { | ||||||
| 				c.Options().Logger.Error(ctx, fmt.Sprintf("%s BeforeLoad error", c.String()), err) | 				c.Options().Logger.Error(ctx, c.String()+" BeforeLoad error", err) | ||||||
| 				if !c.Options().AllowFail { | 				if !c.Options().AllowFail { | ||||||
| 					return err | 					return err | ||||||
| 				} | 				} | ||||||
| @@ -154,7 +153,7 @@ var ( | |||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
| 			if err := fn(ctx, c); err != nil { | 			if err := fn(ctx, c); err != nil { | ||||||
| 				c.Options().Logger.Error(ctx, fmt.Sprintf("%s AfterLoad error", c.String()), err) | 				c.Options().Logger.Error(ctx, c.String()+" AfterLoad error", err) | ||||||
| 				if !c.Options().AllowFail { | 				if !c.Options().AllowFail { | ||||||
| 					return err | 					return err | ||||||
| 				} | 				} | ||||||
| @@ -169,7 +168,7 @@ var ( | |||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
| 			if err := fn(ctx, c); err != nil { | 			if err := fn(ctx, c); err != nil { | ||||||
| 				c.Options().Logger.Error(ctx, fmt.Sprintf("%s BeforeSave error", c.String()), err) | 				c.Options().Logger.Error(ctx, c.String()+" BeforeSave error", err) | ||||||
| 				if !c.Options().AllowFail { | 				if !c.Options().AllowFail { | ||||||
| 					return err | 					return err | ||||||
| 				} | 				} | ||||||
| @@ -184,7 +183,7 @@ var ( | |||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
| 			if err := fn(ctx, c); err != nil { | 			if err := fn(ctx, c); err != nil { | ||||||
| 				c.Options().Logger.Error(ctx, fmt.Sprintf("%s AfterSave error", c.String()), err) | 				c.Options().Logger.Error(ctx, c.String()+" AfterSave error", err) | ||||||
| 				if !c.Options().AllowFail { | 				if !c.Options().AllowFail { | ||||||
| 					return err | 					return err | ||||||
| 				} | 				} | ||||||
| @@ -199,7 +198,7 @@ var ( | |||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
| 			if err := fn(ctx, c); err != nil { | 			if err := fn(ctx, c); err != nil { | ||||||
| 				c.Options().Logger.Error(ctx, fmt.Sprintf("%s BeforeInit error", c.String()), err) | 				c.Options().Logger.Error(ctx, c.String()+" BeforeInit error", err) | ||||||
| 				if !c.Options().AllowFail { | 				if !c.Options().AllowFail { | ||||||
| 					return err | 					return err | ||||||
| 				} | 				} | ||||||
| @@ -214,7 +213,7 @@ var ( | |||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
| 			if err := fn(ctx, c); err != nil { | 			if err := fn(ctx, c); err != nil { | ||||||
| 				c.Options().Logger.Error(ctx, fmt.Sprintf("%s AfterInit error", c.String(), err), err) | 				c.Options().Logger.Error(ctx, c.String()+" AfterInit error", err) | ||||||
| 				if !c.Options().AllowFail { | 				if !c.Options().AllowFail { | ||||||
| 					return err | 					return err | ||||||
| 				} | 				} | ||||||
|   | |||||||
| @@ -5,6 +5,28 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | func TestMultipleUsage(t *testing.T) { | ||||||
|  | 	ctx := context.TODO() | ||||||
|  | 	md := New(0) | ||||||
|  | 	md.Set("key1_1", "val1_1", "key1_2", "val1_2", "key1_3", "val1_3") | ||||||
|  | 	ctx = NewIncomingContext(ctx, Copy(md)) | ||||||
|  | 	ctx = NewOutgoingContext(ctx, Copy(md)) | ||||||
|  | 	imd, _ := FromIncomingContext(ctx) | ||||||
|  | 	omd, _ := FromOutgoingContext(ctx) | ||||||
|  | 	_ = func(x context.Context) context.Context { | ||||||
|  | 		m, _ := FromIncomingContext(x) | ||||||
|  | 		m.Del("key1_2") | ||||||
|  | 		return ctx | ||||||
|  | 	}(ctx) | ||||||
|  | 	_ = func(x context.Context) context.Context { | ||||||
|  | 		m, _ := FromIncomingContext(x) | ||||||
|  | 		m.Del("key1_3") | ||||||
|  | 		return ctx | ||||||
|  | 	}(ctx) | ||||||
|  | 	t.Logf("imd %#+v", imd) | ||||||
|  | 	t.Logf("omd %#+v", omd) | ||||||
|  | } | ||||||
|  |  | ||||||
| func TestMetadataSetMultiple(t *testing.T) { | func TestMetadataSetMultiple(t *testing.T) { | ||||||
| 	md := New(4) | 	md := New(4) | ||||||
| 	md.Set("key1", "val1", "key2", "val2", "key3") | 	md.Set("key1", "val1", "key2", "val2", "key3") | ||||||
|   | |||||||
| @@ -66,6 +66,12 @@ type bro struct { | |||||||
|  |  | ||||||
| func (p *bro) Name() string { return p.name } | func (p *bro) Name() string { return p.name } | ||||||
|  |  | ||||||
|  | func (p *bro) Live() bool { return true } | ||||||
|  |  | ||||||
|  | func (p *bro) Ready() bool { return true } | ||||||
|  |  | ||||||
|  | func (p *bro) Health() bool { return true } | ||||||
|  |  | ||||||
| func (p *bro) Init(opts ...broker.Option) error { return nil } | func (p *bro) Init(opts ...broker.Option) error { return nil } | ||||||
|  |  | ||||||
| // Options returns broker options | // Options returns broker options | ||||||
|   | |||||||
| @@ -45,6 +45,18 @@ type ( | |||||||
| 	tunnelAddr struct{} | 	tunnelAddr struct{} | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | func (t *tunBroker) Live() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *tunBroker) Ready() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *tunBroker) Health() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| func (t *tunBroker) Init(opts ...broker.Option) error { | func (t *tunBroker) Init(opts ...broker.Option) error { | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&t.opts) | 		o(&t.opts) | ||||||
|   | |||||||
| @@ -29,17 +29,32 @@ var ( | |||||||
| // and an abstraction over varying implementations | // and an abstraction over varying implementations | ||||||
| // {consul, etcd, zookeeper, ...} | // {consul, etcd, zookeeper, ...} | ||||||
| type Register interface { | type Register interface { | ||||||
|  | 	// Name returns register name | ||||||
| 	Name() string | 	Name() string | ||||||
|  | 	// Init initialize register | ||||||
| 	Init(...Option) error | 	Init(...Option) error | ||||||
|  | 	// Options returns options for register | ||||||
| 	Options() Options | 	Options() Options | ||||||
|  | 	// Connect initialize connect to register | ||||||
| 	Connect(context.Context) error | 	Connect(context.Context) error | ||||||
|  | 	// Disconnect initialize discconection from register | ||||||
| 	Disconnect(context.Context) error | 	Disconnect(context.Context) error | ||||||
|  | 	// Register service in registry | ||||||
| 	Register(context.Context, *Service, ...RegisterOption) error | 	Register(context.Context, *Service, ...RegisterOption) error | ||||||
|  | 	// Deregister service from registry | ||||||
| 	Deregister(context.Context, *Service, ...DeregisterOption) error | 	Deregister(context.Context, *Service, ...DeregisterOption) error | ||||||
|  | 	// LookupService in registry | ||||||
| 	LookupService(context.Context, string, ...LookupOption) ([]*Service, error) | 	LookupService(context.Context, string, ...LookupOption) ([]*Service, error) | ||||||
|  | 	// ListServices in registry | ||||||
| 	ListServices(context.Context, ...ListOption) ([]*Service, error) | 	ListServices(context.Context, ...ListOption) ([]*Service, error) | ||||||
|  | 	// Watch registry events | ||||||
| 	Watch(context.Context, ...WatchOption) (Watcher, error) | 	Watch(context.Context, ...WatchOption) (Watcher, error) | ||||||
|  | 	// String returns registry string representation | ||||||
| 	String() string | 	String() string | ||||||
|  | 	// Live returns register liveness | ||||||
|  | 	// Live() bool | ||||||
|  | 	// Ready returns register readiness | ||||||
|  | 	// Ready() bool | ||||||
| } | } | ||||||
|  |  | ||||||
| // Service holds service register info | // Service holds service register info | ||||||
|   | |||||||
| @@ -121,6 +121,18 @@ func (n *noopServer) newCodec(contentType string) (codec.Codec, error) { | |||||||
| 	return nil, codec.ErrUnknownContentType | 	return nil, codec.ErrUnknownContentType | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (n *noopServer) Live() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (n *noopServer) Ready() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (n *noopServer) Health() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| func (n *noopServer) Handle(handler Handler) error { | func (n *noopServer) Handle(handler Handler) error { | ||||||
| 	n.h = handler | 	n.h = handler | ||||||
| 	return nil | 	return nil | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ import ( | |||||||
| 	"go.unistack.org/micro/v3/logger" | 	"go.unistack.org/micro/v3/logger" | ||||||
| 	"go.unistack.org/micro/v3/metadata" | 	"go.unistack.org/micro/v3/metadata" | ||||||
| 	"go.unistack.org/micro/v3/meter" | 	"go.unistack.org/micro/v3/meter" | ||||||
| 	"go.unistack.org/micro/v3/network/transport" |  | ||||||
| 	"go.unistack.org/micro/v3/options" | 	"go.unistack.org/micro/v3/options" | ||||||
| 	"go.unistack.org/micro/v3/register" | 	"go.unistack.org/micro/v3/register" | ||||||
| 	msync "go.unistack.org/micro/v3/sync" | 	msync "go.unistack.org/micro/v3/sync" | ||||||
| @@ -37,8 +36,6 @@ type Options struct { | |||||||
| 	Logger logger.Logger | 	Logger logger.Logger | ||||||
| 	// Meter holds the meter | 	// Meter holds the meter | ||||||
| 	Meter meter.Meter | 	Meter meter.Meter | ||||||
| 	// Transport holds the transport |  | ||||||
| 	Transport transport.Transport |  | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 		// Router for requests | 		// Router for requests | ||||||
| @@ -100,7 +97,6 @@ func NewOptions(opts ...Option) Options { | |||||||
| 		Tracer:           tracer.DefaultTracer, | 		Tracer:           tracer.DefaultTracer, | ||||||
| 		Broker:           broker.DefaultBroker, | 		Broker:           broker.DefaultBroker, | ||||||
| 		Register:         register.DefaultRegister, | 		Register:         register.DefaultRegister, | ||||||
| 		Transport:        transport.DefaultTransport, |  | ||||||
| 		Address:          DefaultAddress, | 		Address:          DefaultAddress, | ||||||
| 		Name:             DefaultName, | 		Name:             DefaultName, | ||||||
| 		Version:          DefaultVersion, | 		Version:          DefaultVersion, | ||||||
| @@ -209,13 +205,6 @@ func Tracer(t tracer.Tracer) Option { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // Transport mechanism for communication e.g http, rabbitmq, etc |  | ||||||
| func Transport(t transport.Transport) Option { |  | ||||||
| 	return func(o *Options) { |  | ||||||
| 		o.Transport = t |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Metadata associated with the server | // Metadata associated with the server | ||||||
| func Metadata(md metadata.Metadata) Option { | func Metadata(md metadata.Metadata) Option { | ||||||
| 	return func(o *Options) { | 	return func(o *Options) { | ||||||
| @@ -249,14 +238,6 @@ func TLSConfig(t *tls.Config) Option { | |||||||
| 	return func(o *Options) { | 	return func(o *Options) { | ||||||
| 		// set the internal tls | 		// set the internal tls | ||||||
| 		o.TLSConfig = t | 		o.TLSConfig = t | ||||||
|  |  | ||||||
| 		// set the default transport if one is not |  | ||||||
| 		// already set. Required for Init call below. |  | ||||||
|  |  | ||||||
| 		// set the transport tls |  | ||||||
| 		_ = o.Transport.Init( |  | ||||||
| 			transport.TLSConfig(t), |  | ||||||
| 		) |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -62,6 +62,12 @@ type Server interface { | |||||||
| 	Stop() error | 	Stop() error | ||||||
| 	// Server implementation | 	// Server implementation | ||||||
| 	String() string | 	String() string | ||||||
|  | 	// Live returns server liveness | ||||||
|  | 	Live() bool | ||||||
|  | 	// Ready returns server readiness | ||||||
|  | 	Ready() bool | ||||||
|  | 	// Health returns server health | ||||||
|  | 	Health() bool | ||||||
| } | } | ||||||
|  |  | ||||||
| type ( | type ( | ||||||
|   | |||||||
							
								
								
									
										75
									
								
								service.go
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								service.go
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| // Package micro is a pluggable framework for microservices | // Package micro is a pluggable framework for microservices | ||||||
| package micro // import "go.unistack.org/micro/v3" | package micro | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| @@ -72,8 +72,14 @@ type Service interface { | |||||||
| 	Start() error | 	Start() error | ||||||
| 	// Stop the service | 	// Stop the service | ||||||
| 	Stop() error | 	Stop() error | ||||||
| 	// The service implementation | 	// String service representation | ||||||
| 	String() string | 	String() string | ||||||
|  | 	// Live returns service liveness | ||||||
|  | 	Live() bool | ||||||
|  | 	// Ready returns service readiness | ||||||
|  | 	Ready() bool | ||||||
|  | 	// Health returns service health | ||||||
|  | 	Health() bool | ||||||
| } | } | ||||||
|  |  | ||||||
| // RegisterHandler is syntactic sugar for registering a handler | // RegisterHandler is syntactic sugar for registering a handler | ||||||
| @@ -101,9 +107,7 @@ func (s *service) Name() string { | |||||||
| 	return s.opts.Name | 	return s.opts.Name | ||||||
| } | } | ||||||
|  |  | ||||||
| // Init initialises options. Additionally it calls cmd.Init | // Init initialises options. | ||||||
| // which parses command line flags. cmd.Init is only called |  | ||||||
| // on first Init. |  | ||||||
| // | // | ||||||
| //nolint:gocyclo | //nolint:gocyclo | ||||||
| func (s *service) Init(opts ...Option) error { | func (s *service) Init(opts ...Option) error { | ||||||
| @@ -252,6 +256,63 @@ func (s *service) String() string { | |||||||
| 	return s.opts.Name | 	return s.opts.Name | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (s *service) Live() bool { | ||||||
|  | 	for _, v := range s.opts.Brokers { | ||||||
|  | 		if !v.Live() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, v := range s.opts.Servers { | ||||||
|  | 		if !v.Live() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, v := range s.opts.Stores { | ||||||
|  | 		if !v.Live() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *service) Ready() bool { | ||||||
|  | 	for _, v := range s.opts.Brokers { | ||||||
|  | 		if !v.Ready() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, v := range s.opts.Servers { | ||||||
|  | 		if !v.Ready() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, v := range s.opts.Stores { | ||||||
|  | 		if !v.Ready() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *service) Health() bool { | ||||||
|  | 	for _, v := range s.opts.Brokers { | ||||||
|  | 		if !v.Health() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, v := range s.opts.Servers { | ||||||
|  | 		if !v.Health() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, v := range s.opts.Stores { | ||||||
|  | 		if !v.Health() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| //nolint:gocyclo | //nolint:gocyclo | ||||||
| func (s *service) Start() error { | func (s *service) Start() error { | ||||||
| 	var err error | 	var err error | ||||||
| @@ -281,10 +342,6 @@ func (s *service) Start() error { | |||||||
| 		config.Loggers[0].Info(s.opts.Context, fmt.Sprintf("starting [service] %s version %s", s.Options().Name, s.Options().Version)) | 		config.Loggers[0].Info(s.opts.Context, fmt.Sprintf("starting [service] %s version %s", s.Options().Name, s.Options().Version)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(s.opts.Servers) == 0 { |  | ||||||
| 		return fmt.Errorf("cant start nil server") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, reg := range s.opts.Registers { | 	for _, reg := range s.opts.Registers { | ||||||
| 		if err = reg.Connect(s.opts.Context); err != nil { | 		if err = reg.Connect(s.opts.Context); err != nil { | ||||||
| 			return err | 			return err | ||||||
|   | |||||||
| @@ -149,6 +149,18 @@ func (m *memoryStore) Name() string { | |||||||
| 	return m.opts.Name | 	return m.opts.Name | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (m *memoryStore) Live() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *memoryStore) Ready() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *memoryStore) Health() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| func (m *memoryStore) Exists(ctx context.Context, key string, opts ...store.ExistsOption) error { | func (m *memoryStore) Exists(ctx context.Context, key string, opts ...store.ExistsOption) error { | ||||||
| 	if m.opts.LazyConnect { | 	if m.opts.LazyConnect { | ||||||
| 		if err := m.connect(ctx); err != nil { | 		if err := m.connect(ctx); err != nil { | ||||||
| @@ -279,3 +291,16 @@ func (m *memoryStore) connect(ctx context.Context) error { | |||||||
| 	m.isConnected.CompareAndSwap(0, 1) | 	m.isConnected.CompareAndSwap(0, 1) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (m *memoryStore) Watch(ctx context.Context, opts ...store.WatchOption) (store.Watcher, error) { | ||||||
|  | 	return &watcher{}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type watcher struct{} | ||||||
|  |  | ||||||
|  | func (w *watcher) Next() (store.Event, error) { | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *watcher) Stop() { | ||||||
|  | } | ||||||
|   | |||||||
| @@ -23,6 +23,18 @@ type noopStore struct { | |||||||
| 	isConnected atomic.Int32 | 	isConnected atomic.Int32 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (n *noopStore) Live() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (n *noopStore) Ready() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (n *noopStore) Health() bool { | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| func NewStore(opts ...Option) *noopStore { | func NewStore(opts ...Option) *noopStore { | ||||||
| 	options := NewOptions(opts...) | 	options := NewOptions(opts...) | ||||||
| 	return &noopStore{opts: options} | 	return &noopStore{opts: options} | ||||||
|   | |||||||
| @@ -45,7 +45,14 @@ type Store interface { | |||||||
| 	Disconnect(ctx context.Context) error | 	Disconnect(ctx context.Context) error | ||||||
| 	// String returns the name of the implementation. | 	// String returns the name of the implementation. | ||||||
| 	String() string | 	String() string | ||||||
|  | 	// Watch returns events watcher | ||||||
| 	Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) | 	Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) | ||||||
|  | 	// Live returns store liveness | ||||||
|  | 	Live() bool | ||||||
|  | 	// Ready returns store readiness | ||||||
|  | 	Ready() bool | ||||||
|  | 	// Health returns store health | ||||||
|  | 	Health() bool | ||||||
| } | } | ||||||
|  |  | ||||||
| type ( | type ( | ||||||
|   | |||||||
| @@ -70,3 +70,15 @@ func (w *NamespaceStore) String() string { | |||||||
| func (w *NamespaceStore) Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) { | func (w *NamespaceStore) Watch(ctx context.Context, opts ...WatchOption) (Watcher, error) { | ||||||
| 	return w.s.Watch(ctx, opts...) | 	return w.s.Watch(ctx, opts...) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (w *NamespaceStore) Live() bool { | ||||||
|  | 	return w.s.Live() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *NamespaceStore) Ready() bool { | ||||||
|  | 	return w.s.Ready() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *NamespaceStore) Health() bool { | ||||||
|  | 	return w.s.Health() | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,40 +0,0 @@ | |||||||
| // Package io is for io management |  | ||||||
| package io |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"io" |  | ||||||
|  |  | ||||||
| 	"go.unistack.org/micro/v3/network/transport" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type rwc struct { |  | ||||||
| 	socket transport.Socket |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *rwc) Read(p []byte) (n int, err error) { |  | ||||||
| 	m := new(transport.Message) |  | ||||||
| 	if err := r.socket.Recv(m); err != nil { |  | ||||||
| 		return 0, err |  | ||||||
| 	} |  | ||||||
| 	copy(p, m.Body) |  | ||||||
| 	return len(m.Body), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *rwc) Write(p []byte) (n int, err error) { |  | ||||||
| 	err = r.socket.Send(&transport.Message{ |  | ||||||
| 		Body: p, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return 0, err |  | ||||||
| 	} |  | ||||||
| 	return len(p), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *rwc) Close() error { |  | ||||||
| 	return r.socket.Close() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewRWC returns a new ReadWriteCloser |  | ||||||
| func NewRWC(sock transport.Socket) io.ReadWriteCloser { |  | ||||||
| 	return &rwc{sock} |  | ||||||
| } |  | ||||||
| @@ -1,118 +0,0 @@ | |||||||
| package pool |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"sync" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"go.unistack.org/micro/v3/network/transport" |  | ||||||
| 	"go.unistack.org/micro/v3/util/id" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type pool struct { |  | ||||||
| 	tr    transport.Transport |  | ||||||
| 	conns map[string][]*poolConn |  | ||||||
| 	size  int |  | ||||||
| 	ttl   time.Duration |  | ||||||
| 	sync.Mutex |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type poolConn struct { |  | ||||||
| 	created time.Time |  | ||||||
| 	transport.Client |  | ||||||
| 	id string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newPool(options Options) *pool { |  | ||||||
| 	return &pool{ |  | ||||||
| 		size:  options.Size, |  | ||||||
| 		tr:    options.Transport, |  | ||||||
| 		ttl:   options.TTL, |  | ||||||
| 		conns: make(map[string][]*poolConn), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *pool) Close() error { |  | ||||||
| 	p.Lock() |  | ||||||
| 	for k, c := range p.conns { |  | ||||||
| 		for _, conn := range c { |  | ||||||
| 			conn.Client.Close() |  | ||||||
| 		} |  | ||||||
| 		delete(p.conns, k) |  | ||||||
| 	} |  | ||||||
| 	p.Unlock() |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NoOp the Close since we manage it |  | ||||||
| func (p *poolConn) Close() error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *poolConn) ID() string { |  | ||||||
| 	return p.id |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *poolConn) Created() time.Time { |  | ||||||
| 	return p.created |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *pool) Get(ctx context.Context, addr string, opts ...transport.DialOption) (Conn, error) { |  | ||||||
| 	p.Lock() |  | ||||||
| 	conns := p.conns[addr] |  | ||||||
|  |  | ||||||
| 	// while we have conns check age and then return one |  | ||||||
| 	// otherwise we'll create a new conn |  | ||||||
| 	for len(conns) > 0 { |  | ||||||
| 		conn := conns[len(conns)-1] |  | ||||||
| 		conns = conns[:len(conns)-1] |  | ||||||
| 		p.conns[addr] = conns |  | ||||||
|  |  | ||||||
| 		// if conn is old kill it and move on |  | ||||||
| 		if d := time.Since(conn.Created()); d > p.ttl { |  | ||||||
| 			conn.Client.Close() |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// we got a good conn, lets unlock and return it |  | ||||||
| 		p.Unlock() |  | ||||||
|  |  | ||||||
| 		return conn, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	p.Unlock() |  | ||||||
|  |  | ||||||
| 	// create new conn |  | ||||||
| 	c, err := p.tr.Dial(ctx, addr, opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	id, err := id.New() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &poolConn{ |  | ||||||
| 		Client:  c, |  | ||||||
| 		id:      id, |  | ||||||
| 		created: time.Now(), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *pool) Release(conn Conn, err error) error { |  | ||||||
| 	// don't store the conn if it has errored |  | ||||||
| 	if err != nil { |  | ||||||
| 		return conn.(*poolConn).Client.Close() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// otherwise put it back for reuse |  | ||||||
| 	p.Lock() |  | ||||||
| 	conns := p.conns[conn.Remote()] |  | ||||||
| 	if len(conns) >= p.size { |  | ||||||
| 		p.Unlock() |  | ||||||
| 		return conn.(*poolConn).Client.Close() |  | ||||||
| 	} |  | ||||||
| 	p.conns[conn.Remote()] = append(conns, conn.(*poolConn)) |  | ||||||
| 	p.Unlock() |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,92 +0,0 @@ | |||||||
| //go:build ignore |  | ||||||
| // +build ignore |  | ||||||
|  |  | ||||||
| package pool |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"testing" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"go.unistack.org/micro/v3/network/transport" |  | ||||||
| 	"go.unistack.org/micro/v3/network/transport/memory" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func testPool(t *testing.T, size int, ttl time.Duration) { |  | ||||||
| 	// mock transport |  | ||||||
| 	tr := memory.NewTransport() |  | ||||||
|  |  | ||||||
| 	options := Options{ |  | ||||||
| 		TTL:       ttl, |  | ||||||
| 		Size:      size, |  | ||||||
| 		Transport: tr, |  | ||||||
| 	} |  | ||||||
| 	// zero pool |  | ||||||
| 	p := newPool(options) |  | ||||||
|  |  | ||||||
| 	// listen |  | ||||||
| 	l, err := tr.Listen(":0") |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	defer l.Close() |  | ||||||
|  |  | ||||||
| 	// accept loop |  | ||||||
| 	go func() { |  | ||||||
| 		for { |  | ||||||
| 			if err := l.Accept(func(s transport.Socket) { |  | ||||||
| 				for { |  | ||||||
| 					var msg transport.Message |  | ||||||
| 					if err := s.Recv(&msg); err != nil { |  | ||||||
| 						return |  | ||||||
| 					} |  | ||||||
| 					if err := s.Send(&msg); err != nil { |  | ||||||
| 						return |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}); err != nil { |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
|  |  | ||||||
| 	for i := 0; i < 10; i++ { |  | ||||||
| 		// get a conn |  | ||||||
| 		c, err := p.Get(l.Addr()) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatal(err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		msg := &transport.Message{ |  | ||||||
| 			Body: []byte(`hello world`), |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if err := c.Send(msg); err != nil { |  | ||||||
| 			t.Fatal(err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		var rcv transport.Message |  | ||||||
|  |  | ||||||
| 		if err := c.Recv(&rcv); err != nil { |  | ||||||
| 			t.Fatal(err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if string(rcv.Body) != string(msg.Body) { |  | ||||||
| 			t.Fatalf("got %v, expected %v", rcv.Body, msg.Body) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// release the conn |  | ||||||
| 		p.Release(c, nil) |  | ||||||
|  |  | ||||||
| 		p.Lock() |  | ||||||
| 		if i := len(p.conns[l.Addr()]); i > size { |  | ||||||
| 			p.Unlock() |  | ||||||
| 			t.Fatalf("pool size %d is greater than expected %d", i, size) |  | ||||||
| 		} |  | ||||||
| 		p.Unlock() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestClientPool(t *testing.T) { |  | ||||||
| 	testPool(t, 0, time.Minute) |  | ||||||
| 	testPool(t, 2, time.Minute) |  | ||||||
| } |  | ||||||
| @@ -1,38 +0,0 @@ | |||||||
| package pool |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"go.unistack.org/micro/v3/network/transport" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Options struct |  | ||||||
| type Options struct { |  | ||||||
| 	Transport transport.Transport |  | ||||||
| 	TTL       time.Duration |  | ||||||
| 	Size      int |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Option func signature |  | ||||||
| type Option func(*Options) |  | ||||||
|  |  | ||||||
| // Size sets the size |  | ||||||
| func Size(i int) Option { |  | ||||||
| 	return func(o *Options) { |  | ||||||
| 		o.Size = i |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Transport sets the transport |  | ||||||
| func Transport(t transport.Transport) Option { |  | ||||||
| 	return func(o *Options) { |  | ||||||
| 		o.Transport = t |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // TTL specifies ttl |  | ||||||
| func TTL(t time.Duration) Option { |  | ||||||
| 	return func(o *Options) { |  | ||||||
| 		o.TTL = t |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,38 +0,0 @@ | |||||||
| // Package pool is a connection pool |  | ||||||
| package pool |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"go.unistack.org/micro/v3/network/transport" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Pool is an interface for connection pooling |  | ||||||
| type Pool interface { |  | ||||||
| 	// Close the pool |  | ||||||
| 	Close() error |  | ||||||
| 	// Get a connection |  | ||||||
| 	Get(ctx context.Context, addr string, opts ...transport.DialOption) (Conn, error) |  | ||||||
| 	// Release the connection |  | ||||||
| 	Release(c Conn, status error) error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Conn conn pool interface |  | ||||||
| type Conn interface { |  | ||||||
| 	// unique id of connection |  | ||||||
| 	ID() string |  | ||||||
| 	// time it was created |  | ||||||
| 	Created() time.Time |  | ||||||
| 	// embedded connection |  | ||||||
| 	transport.Client |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewPool creates new connection pool |  | ||||||
| func NewPool(opts ...Option) Pool { |  | ||||||
| 	options := Options{} |  | ||||||
| 	for _, o := range opts { |  | ||||||
| 		o(&options) |  | ||||||
| 	} |  | ||||||
| 	return newPool(options) |  | ||||||
| } |  | ||||||
| @@ -23,7 +23,7 @@ func TestMarshalYAML(t *testing.T) { | |||||||
|  |  | ||||||
| func TestUnmarshalYAML(t *testing.T) { | func TestUnmarshalYAML(t *testing.T) { | ||||||
| 	type str struct { | 	type str struct { | ||||||
| 		TTL Duration `yaml:"ttl"` | 		TTL *Duration `yaml:"ttl"` | ||||||
| 	} | 	} | ||||||
| 	v := &str{} | 	v := &str{} | ||||||
| 	var err error | 	var err error | ||||||
| @@ -31,14 +31,14 @@ func TestUnmarshalYAML(t *testing.T) { | |||||||
| 	err = yaml.Unmarshal([]byte(`{"ttl":"10ms"}`), v) | 	err = yaml.Unmarshal([]byte(`{"ttl":"10ms"}`), v) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} else if v.TTL != 10000000 { | 	} else if *(v.TTL) != 10000000 { | ||||||
| 		t.Fatalf("invalid duration %v != 10000000", v.TTL) | 		t.Fatalf("invalid duration %v != 10000000", v.TTL) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = yaml.Unmarshal([]byte(`{"ttl":"1y"}`), v) | 	err = yaml.Unmarshal([]byte(`{"ttl":"1y"}`), v) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} else if v.TTL != 31622400000000000 { | 	} else if *(v.TTL) != 31622400000000000 { | ||||||
| 		t.Fatalf("invalid duration %v != 31622400000000000", v.TTL) | 		t.Fatalf("invalid duration %v != 31622400000000000", v.TTL) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user