cleanup interfaces for v4
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
@@ -33,16 +33,6 @@ func SetOption(k, v interface{}) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// SetSubscriberOption returns a function to setup a context with given value
|
||||
func SetSubscriberOption(k, v interface{}) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// SetHandlerOption returns a function to setup a context with given value
|
||||
func SetHandlerOption(k, v interface{}) HandlerOption {
|
||||
return func(o *HandlerOptions) {
|
||||
|
@@ -51,14 +51,3 @@ func TestSetOption(t *testing.T) {
|
||||
t.Fatal("SetOption not works")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetSubscriberOption(t *testing.T) {
|
||||
type key struct{}
|
||||
o := SetSubscriberOption(key{}, "test")
|
||||
opts := &SubscriberOptions{}
|
||||
o(opts)
|
||||
|
||||
if v, ok := opts.Context.Value(key{}).(string); !ok || v == "" {
|
||||
t.Fatal("SetSubscriberOption not works")
|
||||
}
|
||||
}
|
||||
|
@@ -1,59 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"go.unistack.org/micro/v4/register"
|
||||
)
|
||||
|
||||
type rpcHandler struct {
|
||||
opts HandlerOptions
|
||||
handler interface{}
|
||||
name string
|
||||
endpoints []*register.Endpoint
|
||||
}
|
||||
|
||||
func newRPCHandler(handler interface{}, opts ...HandlerOption) Handler {
|
||||
options := NewHandlerOptions(opts...)
|
||||
|
||||
typ := reflect.TypeOf(handler)
|
||||
hdlr := reflect.ValueOf(handler)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
var endpoints []*register.Endpoint
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
if e := register.ExtractEndpoint(typ.Method(m)); e != nil {
|
||||
e.Name = name + "." + e.Name
|
||||
|
||||
for k, v := range options.Metadata[e.Name] {
|
||||
e.Metadata[k] = v
|
||||
}
|
||||
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
}
|
||||
|
||||
return &rpcHandler{
|
||||
name: name,
|
||||
handler: handler,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Handler() interface{} {
|
||||
return r.handler
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Endpoints() []*register.Endpoint {
|
||||
return r.endpoints
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Options() HandlerOptions {
|
||||
return r.opts
|
||||
}
|
199
server/noop.go
199
server/noop.go
@@ -1,12 +1,11 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.unistack.org/micro/v4/broker"
|
||||
"go.unistack.org/micro/v4/codec"
|
||||
"go.unistack.org/micro/v4/logger"
|
||||
"go.unistack.org/micro/v4/register"
|
||||
@@ -25,13 +24,12 @@ const (
|
||||
)
|
||||
|
||||
type noopServer struct {
|
||||
h Handler
|
||||
wg *sync.WaitGroup
|
||||
rsvc *register.Service
|
||||
handlers map[string]Handler
|
||||
subscribers map[*subscriber][]broker.Subscriber
|
||||
exit chan chan error
|
||||
opts Options
|
||||
h Handler
|
||||
wg *sync.WaitGroup
|
||||
rsvc *register.Service
|
||||
handlers map[string]Handler
|
||||
exit chan chan error
|
||||
opts Options
|
||||
sync.RWMutex
|
||||
registered bool
|
||||
started bool
|
||||
@@ -43,9 +41,6 @@ func NewServer(opts ...Option) Server {
|
||||
if n.handlers == nil {
|
||||
n.handlers = make(map[string]Handler)
|
||||
}
|
||||
if n.subscribers == nil {
|
||||
n.subscribers = make(map[*subscriber][]broker.Subscriber)
|
||||
}
|
||||
if n.exit == nil {
|
||||
n.exit = make(chan chan error)
|
||||
}
|
||||
@@ -71,37 +66,10 @@ func (n *noopServer) Name() string {
|
||||
return n.opts.Name
|
||||
}
|
||||
|
||||
func (n *noopServer) Subscribe(sb Subscriber) error {
|
||||
sub, ok := sb.(*subscriber)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid subscriber: expected *subscriber")
|
||||
} else if len(sub.handlers) == 0 {
|
||||
return fmt.Errorf("invalid subscriber: no handler functions")
|
||||
}
|
||||
|
||||
if err := ValidateSubscriber(sb); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
if _, ok = n.subscribers[sub]; ok {
|
||||
n.Unlock()
|
||||
return fmt.Errorf("subscriber %v already exists", sub)
|
||||
}
|
||||
|
||||
n.subscribers[sub] = nil
|
||||
n.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *noopServer) NewHandler(h interface{}, opts ...HandlerOption) Handler {
|
||||
return newRPCHandler(h, opts...)
|
||||
}
|
||||
|
||||
func (n *noopServer) NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber {
|
||||
return newSubscriber(topic, sb, opts...)
|
||||
}
|
||||
|
||||
func (n *noopServer) Init(opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o(&n.opts)
|
||||
@@ -110,9 +78,6 @@ func (n *noopServer) Init(opts ...Option) error {
|
||||
if n.handlers == nil {
|
||||
n.handlers = make(map[string]Handler, 1)
|
||||
}
|
||||
if n.subscribers == nil {
|
||||
n.subscribers = make(map[*subscriber][]broker.Subscriber, 1)
|
||||
}
|
||||
|
||||
if n.exit == nil {
|
||||
n.exit = make(chan chan error)
|
||||
@@ -158,21 +123,10 @@ func (n *noopServer) Register() error {
|
||||
|
||||
sort.Strings(handlerList)
|
||||
|
||||
subscriberList := make([]*subscriber, 0, len(n.subscribers))
|
||||
for e := range n.subscribers {
|
||||
subscriberList = append(subscriberList, e)
|
||||
}
|
||||
sort.Slice(subscriberList, func(i, j int) bool {
|
||||
return subscriberList[i].topic > subscriberList[j].topic
|
||||
})
|
||||
|
||||
endpoints := make([]*register.Endpoint, 0, len(handlerList)+len(subscriberList))
|
||||
endpoints := make([]*register.Endpoint, 0, len(handlerList))
|
||||
for _, h := range handlerList {
|
||||
endpoints = append(endpoints, n.handlers[h].Endpoints()...)
|
||||
}
|
||||
for _, e := range subscriberList {
|
||||
endpoints = append(endpoints, e.Endpoints()...)
|
||||
}
|
||||
n.RUnlock()
|
||||
|
||||
service.Nodes[0].Metadata["protocol"] = "noop"
|
||||
@@ -202,39 +156,6 @@ func (n *noopServer) Register() error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
cx := config.Context
|
||||
|
||||
var sub broker.Subscriber
|
||||
|
||||
for sb := range n.subscribers {
|
||||
if sb.Options().Context != nil {
|
||||
cx = sb.Options().Context
|
||||
}
|
||||
|
||||
opts := []broker.SubscribeOption{broker.SubscribeContext(cx), broker.SubscribeAutoAck(sb.Options().AutoAck)}
|
||||
if queue := sb.Options().Queue; len(queue) > 0 {
|
||||
opts = append(opts, broker.SubscribeGroup(queue))
|
||||
}
|
||||
|
||||
if sb.Options().Batch {
|
||||
// batch processing handler
|
||||
sub, err = config.Broker.BatchSubscribe(cx, sb.Topic(), n.newBatchSubHandler(sb, config), opts...)
|
||||
} else {
|
||||
// single processing handler
|
||||
sub, err = config.Broker.Subscribe(cx, sb.Topic(), n.newSubHandler(sb, config), opts...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.Logger.V(logger.InfoLevel) {
|
||||
config.Logger.Infof(n.opts.Context, "subscribing to topic: %s", sb.Topic())
|
||||
}
|
||||
|
||||
n.subscribers[sb] = []broker.Subscriber{sub}
|
||||
}
|
||||
|
||||
n.registered = true
|
||||
if cacheService {
|
||||
n.rsvc = service
|
||||
@@ -273,33 +194,6 @@ func (n *noopServer) Deregister() error {
|
||||
|
||||
n.registered = false
|
||||
|
||||
cx := config.Context
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
for sb, subs := range n.subscribers {
|
||||
for idx := range subs {
|
||||
if sb.Options().Context != nil {
|
||||
cx = sb.Options().Context
|
||||
}
|
||||
|
||||
ncx := cx
|
||||
wg.Add(1)
|
||||
go func(s broker.Subscriber) {
|
||||
defer wg.Done()
|
||||
if config.Logger.V(logger.InfoLevel) {
|
||||
config.Logger.Infof(n.opts.Context, "unsubscribing from topic: %s", s.Topic())
|
||||
}
|
||||
if err := s.Unsubscribe(ncx); err != nil {
|
||||
if config.Logger.V(logger.ErrorLevel) {
|
||||
config.Logger.Errorf(n.opts.Context, "unsubscribing from topic: %s err: %v", s.Topic(), err)
|
||||
}
|
||||
}
|
||||
}(subs[idx])
|
||||
}
|
||||
n.subscribers[sb] = nil
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
n.Unlock()
|
||||
return nil
|
||||
}
|
||||
@@ -336,21 +230,6 @@ func (n *noopServer) Start() error {
|
||||
}
|
||||
n.Unlock()
|
||||
|
||||
// only connect if we're subscribed
|
||||
if len(n.subscribers) > 0 {
|
||||
// connect to the broker
|
||||
if err := config.Broker.Connect(config.Context); err != nil {
|
||||
if config.Logger.V(logger.ErrorLevel) {
|
||||
config.Logger.Errorf(n.opts.Context, "broker [%s] connect error: %v", config.Broker.String(), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if config.Logger.V(logger.InfoLevel) {
|
||||
config.Logger.Infof(n.opts.Context, "broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())
|
||||
}
|
||||
}
|
||||
|
||||
// use RegisterCheck func before register
|
||||
// nolint: nestif
|
||||
if err := config.RegisterCheck(config.Context); err != nil {
|
||||
@@ -429,16 +308,6 @@ func (n *noopServer) Start() error {
|
||||
|
||||
// close transport
|
||||
ch <- nil
|
||||
|
||||
if config.Logger.V(logger.InfoLevel) {
|
||||
config.Logger.Infof(n.opts.Context, "broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address())
|
||||
}
|
||||
// disconnect broker
|
||||
if err := config.Broker.Disconnect(config.Context); err != nil {
|
||||
if config.Logger.V(logger.ErrorLevel) {
|
||||
config.Logger.Errorf(n.opts.Context, "broker [%s] disconnect error: %v", config.Broker.String(), err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// mark the server as started
|
||||
@@ -468,3 +337,55 @@ func (n *noopServer) Stop() error {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type rpcHandler struct {
|
||||
opts HandlerOptions
|
||||
handler interface{}
|
||||
name string
|
||||
endpoints []*register.Endpoint
|
||||
}
|
||||
|
||||
func newRPCHandler(handler interface{}, opts ...HandlerOption) Handler {
|
||||
options := NewHandlerOptions(opts...)
|
||||
|
||||
typ := reflect.TypeOf(handler)
|
||||
hdlr := reflect.ValueOf(handler)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
var endpoints []*register.Endpoint
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
if e := register.ExtractEndpoint(typ.Method(m)); e != nil {
|
||||
e.Name = name + "." + e.Name
|
||||
|
||||
for k, v := range options.Metadata[e.Name] {
|
||||
e.Metadata[k] = v
|
||||
}
|
||||
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
}
|
||||
|
||||
return &rpcHandler{
|
||||
name: name,
|
||||
handler: handler,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Handler() interface{} {
|
||||
return r.handler
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Endpoints() []*register.Endpoint {
|
||||
return r.endpoints
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Options() HandlerOptions {
|
||||
return r.opts
|
||||
}
|
||||
|
@@ -1,104 +0,0 @@
|
||||
package server_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"go.unistack.org/micro/v4/broker"
|
||||
"go.unistack.org/micro/v4/client"
|
||||
"go.unistack.org/micro/v4/codec"
|
||||
"go.unistack.org/micro/v4/logger"
|
||||
"go.unistack.org/micro/v4/metadata"
|
||||
"go.unistack.org/micro/v4/server"
|
||||
)
|
||||
|
||||
type TestHandler struct {
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
type TestMessage struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (h *TestHandler) SingleSubHandler(ctx context.Context, msg *codec.Frame) error {
|
||||
// fmt.Printf("msg %s\n", msg.Data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestHandler) BatchSubHandler(ctxs []context.Context, msgs []*codec.Frame) error {
|
||||
if len(msgs) != 8 {
|
||||
h.t.Fatal("invalid number of messages received")
|
||||
}
|
||||
for idx := 0; idx < len(msgs); idx++ {
|
||||
md, _ := metadata.FromIncomingContext(ctxs[idx])
|
||||
_ = md
|
||||
// fmt.Printf("msg md %v\n", md)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestNoopSub(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
b := broker.NewBroker()
|
||||
|
||||
if err := b.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := b.Connect(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
logger.DefaultLogger.Init(logger.WithLevel(logger.ErrorLevel))
|
||||
s := server.NewServer(
|
||||
server.Broker(b),
|
||||
server.Codec("application/octet-stream", codec.NewCodec()),
|
||||
)
|
||||
if err := s.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := client.NewClient(
|
||||
client.Broker(b),
|
||||
client.Codec("application/octet-stream", codec.NewCodec()),
|
||||
client.ContentType("application/octet-stream"),
|
||||
)
|
||||
if err := c.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
h := &TestHandler{t: t}
|
||||
|
||||
if err := s.Subscribe(s.NewSubscriber("single_topic", h.SingleSubHandler,
|
||||
server.SubscriberQueue("queue"),
|
||||
)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := s.Subscribe(s.NewSubscriber("batch_topic", h.BatchSubHandler,
|
||||
server.SubscriberQueue("queue"),
|
||||
server.SubscriberBatch(true),
|
||||
)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msgs := make([]client.Message, 0, 8)
|
||||
for i := 0; i < 8; i++ {
|
||||
msgs = append(msgs, c.NewMessage("batch_topic", &codec.Frame{Data: []byte(fmt.Sprintf(`{"name": "test_name %d"}`, i))}))
|
||||
}
|
||||
|
||||
if err := c.BatchPublish(ctx, msgs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := s.Stop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
}
|
@@ -7,7 +7,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.unistack.org/micro/v4/broker"
|
||||
"go.unistack.org/micro/v4/codec"
|
||||
"go.unistack.org/micro/v4/logger"
|
||||
"go.unistack.org/micro/v4/metadata"
|
||||
@@ -19,6 +18,17 @@ import (
|
||||
"go.unistack.org/micro/v4/util/id"
|
||||
)
|
||||
|
||||
var (
|
||||
// ServerRequestDurationSeconds specifies meter metric name
|
||||
ServerRequestDurationSeconds = "server_request_duration_seconds"
|
||||
// ServerRequestLatencyMicroseconds specifies meter metric name
|
||||
ServerRequestLatencyMicroseconds = "server_request_latency_microseconds"
|
||||
// ServerRequestTotal specifies meter metric name
|
||||
ServerRequestTotal = "server_request_total"
|
||||
// ServerRequestInflight specifies meter metric name
|
||||
ServerRequestInflight = "server_request_inflight"
|
||||
)
|
||||
|
||||
// Option func
|
||||
type Option func(*Options)
|
||||
|
||||
@@ -26,8 +36,6 @@ type Option func(*Options)
|
||||
type Options struct {
|
||||
// Context holds the external options and can be used for server shutdown
|
||||
Context context.Context
|
||||
// Broker holds the server broker
|
||||
Broker broker.Broker
|
||||
// Register holds the register
|
||||
Register register.Register
|
||||
// Tracer holds the tracer
|
||||
@@ -38,12 +46,6 @@ type Options struct {
|
||||
Meter meter.Meter
|
||||
// Transport holds the transport
|
||||
Transport transport.Transport
|
||||
|
||||
/*
|
||||
// Router for requests
|
||||
Router Router
|
||||
*/
|
||||
|
||||
// Listener may be passed if already created
|
||||
Listener net.Listener
|
||||
// Wait group
|
||||
@@ -68,10 +70,6 @@ type Options struct {
|
||||
Advertise string
|
||||
// Version holds the server version
|
||||
Version string
|
||||
// SubWrappers holds the server subscribe wrappers
|
||||
SubWrappers []SubscriberWrapper
|
||||
// BatchSubWrappers holds the server batch subscribe wrappers
|
||||
BatchSubWrappers []BatchSubscriberWrapper
|
||||
// HdlrWrappers holds the handler wrappers
|
||||
HdlrWrappers []HandlerWrapper
|
||||
// RegisterAttempts holds the number of register attempts before error
|
||||
@@ -84,7 +82,7 @@ type Options struct {
|
||||
MaxConn int
|
||||
// DeregisterAttempts holds the number of deregister attempts before error
|
||||
DeregisterAttempts int
|
||||
// Hooks may contains SubscriberWrapper, HandlerWrapper or Server func wrapper
|
||||
// Hooks may contains HandlerWrapper or Server func wrapper
|
||||
Hooks options.Hooks
|
||||
}
|
||||
|
||||
@@ -100,7 +98,6 @@ func NewOptions(opts ...Option) Options {
|
||||
Logger: logger.DefaultLogger,
|
||||
Meter: meter.DefaultMeter,
|
||||
Tracer: tracer.DefaultTracer,
|
||||
Broker: broker.DefaultBroker,
|
||||
Register: register.DefaultRegister,
|
||||
Transport: transport.DefaultTransport,
|
||||
Address: DefaultAddress,
|
||||
@@ -173,13 +170,6 @@ func Advertise(a string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Broker to use for pub/sub
|
||||
func Broker(b broker.Broker) Option {
|
||||
return func(o *Options) {
|
||||
o.Broker = b
|
||||
}
|
||||
}
|
||||
|
||||
// Codec to use to encode/decode requests for a given content type
|
||||
func Codec(contentType string, c codec.Codec) Option {
|
||||
return func(o *Options) {
|
||||
@@ -261,15 +251,6 @@ func TLSConfig(t *tls.Config) Option {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// WithRouter sets the request router
|
||||
func WithRouter(r Router) Option {
|
||||
return func(o *Options) {
|
||||
o.Router = r
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Wait tells the server to wait for requests to finish before exiting
|
||||
// If `wg` is nil, server only wait for completion of rpc handler.
|
||||
// For user need finer grained control, pass a concrete `wg` here, server will
|
||||
@@ -290,20 +271,6 @@ func WrapHandler(w HandlerWrapper) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WrapSubscriber adds a subscriber Wrapper to a list of options passed into the server
|
||||
func WrapSubscriber(w SubscriberWrapper) Option {
|
||||
return func(o *Options) {
|
||||
o.SubWrappers = append(o.SubWrappers, w)
|
||||
}
|
||||
}
|
||||
|
||||
// WrapBatchSubscriber adds a batch subscriber Wrapper to a list of options passed into the server
|
||||
func WrapBatchSubscriber(w BatchSubscriberWrapper) Option {
|
||||
return func(o *Options) {
|
||||
o.BatchSubWrappers = append(o.BatchSubWrappers, w)
|
||||
}
|
||||
}
|
||||
|
||||
// MaxConn specifies maximum number of max simultaneous connections to server
|
||||
func MaxConn(n int) Option {
|
||||
return func(o *Options) {
|
||||
@@ -343,41 +310,6 @@ func NewHandlerOptions(opts ...HandlerOption) HandlerOptions {
|
||||
return options
|
||||
}
|
||||
|
||||
// SubscriberOption func
|
||||
type SubscriberOption func(*SubscriberOptions)
|
||||
|
||||
// SubscriberOptions struct
|
||||
type SubscriberOptions struct {
|
||||
// Context holds the external options
|
||||
Context context.Context
|
||||
// Queue holds the subscription queue
|
||||
Queue string
|
||||
// AutoAck flag for auto ack messages after processing
|
||||
AutoAck bool
|
||||
// BodyOnly flag specifies that message without headers
|
||||
BodyOnly bool
|
||||
// Batch flag specifies that message processed in batches
|
||||
Batch bool
|
||||
// BatchSize flag specifies max size of batch
|
||||
BatchSize int
|
||||
// BatchWait flag specifies max wait time for batch filling
|
||||
BatchWait time.Duration
|
||||
}
|
||||
|
||||
// NewSubscriberOptions create new SubscriberOptions
|
||||
func NewSubscriberOptions(opts ...SubscriberOption) SubscriberOptions {
|
||||
options := SubscriberOptions{
|
||||
AutoAck: true,
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// EndpointMetadata is a Handler option that allows metadata to be added to
|
||||
// individual endpoints.
|
||||
func EndpointMetadata(name string, md metadata.Metadata) HandlerOption {
|
||||
@@ -385,68 +317,3 @@ func EndpointMetadata(name string, md metadata.Metadata) HandlerOption {
|
||||
o.Metadata[name] = metadata.Copy(md)
|
||||
}
|
||||
}
|
||||
|
||||
// DisableAutoAck will disable auto acking of messages
|
||||
// after they have been handled.
|
||||
func DisableAutoAck() SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.AutoAck = false
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriberQueue sets the shared queue name distributed messages across subscribers
|
||||
func SubscriberQueue(n string) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.Queue = n
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriberGroup sets the shared group name distributed messages across subscribers
|
||||
func SubscriberGroup(n string) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.Queue = n
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriberBodyOnly says broker that message contains raw data with absence of micro broker.Message format
|
||||
func SubscriberBodyOnly(b bool) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.BodyOnly = b
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriberContext set context options to allow broker SubscriberOption passed
|
||||
func SubscriberContext(ctx context.Context) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriberAck control auto ack processing for handler
|
||||
func SubscriberAck(b bool) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.AutoAck = b
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriberBatch control batch processing for handler
|
||||
func SubscriberBatch(b bool) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.Batch = b
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriberBatchSize control batch filling size for handler
|
||||
// Batch filling max waiting time controlled by SubscriberBatchWait
|
||||
func SubscriberBatchSize(n int) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.BatchSize = n
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriberBatchWait control batch filling wait time for handler
|
||||
func SubscriberBatchWait(td time.Duration) SubscriberOption {
|
||||
return func(o *SubscriberOptions) {
|
||||
o.BatchWait = td
|
||||
}
|
||||
}
|
||||
|
@@ -78,7 +78,6 @@ func NewRegisterService(s Server) (*register.Service, error) {
|
||||
node.Metadata = metadata.Copy(opts.Metadata)
|
||||
|
||||
node.Metadata["server"] = s.String()
|
||||
node.Metadata["broker"] = opts.Broker.String()
|
||||
node.Metadata["register"] = opts.Register.String()
|
||||
|
||||
return ®ister.Service{
|
||||
|
@@ -1,35 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"go.unistack.org/micro/v4/codec"
|
||||
"go.unistack.org/micro/v4/metadata"
|
||||
)
|
||||
|
||||
type rpcMessage struct {
|
||||
payload interface{}
|
||||
codec codec.Codec
|
||||
header metadata.Metadata
|
||||
topic string
|
||||
contentType string
|
||||
body []byte
|
||||
}
|
||||
|
||||
func (r *rpcMessage) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Topic() string {
|
||||
return r.topic
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Body() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Header() metadata.Metadata {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Codec() codec.Codec {
|
||||
return r.codec
|
||||
}
|
@@ -48,10 +48,6 @@ type Server interface {
|
||||
Handle(h Handler) error
|
||||
// Create a new handler
|
||||
NewHandler(h interface{}, opts ...HandlerOption) Handler
|
||||
// Create a new subscriber
|
||||
NewSubscriber(topic string, h interface{}, opts ...SubscriberOption) Subscriber
|
||||
// Register a subscriber
|
||||
Subscribe(s Subscriber) error
|
||||
// Start the server
|
||||
Start() error
|
||||
// Stop the server
|
||||
@@ -60,30 +56,6 @@ type Server interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
/*
|
||||
// Router handle serving messages
|
||||
type Router interface {
|
||||
// ProcessMessage processes a message
|
||||
ProcessMessage(ctx context.Context, msg Message) error
|
||||
// ServeRequest processes a request to completion
|
||||
ServeRequest(ctx context.Context, req Request, rsp Response) error
|
||||
}
|
||||
*/
|
||||
|
||||
// Message is an async message interface
|
||||
type Message interface {
|
||||
// Topic of the message
|
||||
Topic() string
|
||||
// The decoded payload value
|
||||
Body() interface{}
|
||||
// The content type of the payload
|
||||
ContentType() string
|
||||
// The raw headers of the message
|
||||
Header() metadata.Metadata
|
||||
// Codec used to decode the message
|
||||
Codec() codec.Codec
|
||||
}
|
||||
|
||||
// Request is a synchronous request interface
|
||||
type Request interface {
|
||||
// Service name requested
|
||||
@@ -156,13 +128,3 @@ type Handler interface {
|
||||
Endpoints() []*register.Endpoint
|
||||
Options() HandlerOptions
|
||||
}
|
||||
|
||||
// Subscriber interface represents a subscription to a given topic using
|
||||
// a specific subscriber function or object with endpoints. It mirrors
|
||||
// the handler in its behaviour.
|
||||
type Subscriber interface {
|
||||
Topic() string
|
||||
Subscriber() interface{}
|
||||
Endpoints() []*register.Endpoint
|
||||
Options() SubscriberOptions
|
||||
}
|
||||
|
@@ -1,440 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"go.unistack.org/micro/v4/broker"
|
||||
"go.unistack.org/micro/v4/codec"
|
||||
"go.unistack.org/micro/v4/errors"
|
||||
"go.unistack.org/micro/v4/logger"
|
||||
"go.unistack.org/micro/v4/metadata"
|
||||
"go.unistack.org/micro/v4/register"
|
||||
)
|
||||
|
||||
const (
|
||||
subSig = "func(context.Context, interface{}) error"
|
||||
batchSubSig = "func([]context.Context, []interface{}) error"
|
||||
)
|
||||
|
||||
// Precompute the reflect type for error. Can't use error directly
|
||||
// because Typeof takes an empty interface value. This is annoying.
|
||||
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
||||
|
||||
type handler struct {
|
||||
reqType reflect.Type
|
||||
ctxType reflect.Type
|
||||
method reflect.Value
|
||||
}
|
||||
|
||||
type subscriber struct {
|
||||
typ reflect.Type
|
||||
subscriber interface{}
|
||||
topic string
|
||||
endpoints []*register.Endpoint
|
||||
handlers []*handler
|
||||
opts SubscriberOptions
|
||||
rcvr reflect.Value
|
||||
}
|
||||
|
||||
// Is this an exported - upper case - name?
|
||||
func isExported(name string) bool {
|
||||
rune, _ := utf8.DecodeRuneInString(name)
|
||||
return unicode.IsUpper(rune)
|
||||
}
|
||||
|
||||
// Is this type exported or a builtin?
|
||||
func isExportedOrBuiltinType(t reflect.Type) bool {
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// PkgPath will be non-empty even for an exported type,
|
||||
// so we need to check the type name as well.
|
||||
return isExported(t.Name()) || t.PkgPath() == ""
|
||||
}
|
||||
|
||||
// ValidateSubscriber func signature
|
||||
func ValidateSubscriber(sub Subscriber) error {
|
||||
typ := reflect.TypeOf(sub.Subscriber())
|
||||
var argType reflect.Type
|
||||
switch typ.Kind() {
|
||||
case reflect.Func:
|
||||
name := "Func"
|
||||
switch typ.NumIn() {
|
||||
case 2:
|
||||
argType = typ.In(1)
|
||||
if sub.Options().Batch {
|
||||
if argType.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("subscriber %v dont have required signature %s", name, batchSubSig)
|
||||
}
|
||||
if strings.Compare(fmt.Sprintf("%v", argType), "[]interface{}") == 0 {
|
||||
return fmt.Errorf("subscriber %v dont have required signaure %s", name, batchSubSig)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s or %s", name, typ.NumIn(), subSig, batchSubSig)
|
||||
}
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("subscriber %v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if typ.NumOut() != 1 {
|
||||
return fmt.Errorf("subscriber %v has wrong number of return values: %v require signature %s or %s",
|
||||
name, typ.NumOut(), subSig, batchSubSig)
|
||||
}
|
||||
if returnType := typ.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String())
|
||||
}
|
||||
default:
|
||||
hdlr := reflect.ValueOf(sub.Subscriber())
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
switch method.Type.NumIn() {
|
||||
case 3:
|
||||
argType = method.Type.In(2)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s or %s",
|
||||
name, method.Name, method.Type.NumIn(), subSig, batchSubSig)
|
||||
}
|
||||
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("%v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if method.Type.NumOut() != 1 {
|
||||
return fmt.Errorf(
|
||||
"subscriber %v.%v has wrong number of return values: %v require signature %s or %s",
|
||||
name, method.Name, method.Type.NumOut(), subSig, batchSubSig)
|
||||
}
|
||||
if returnType := method.Type.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v.%v returns %v not error", name, method.Name, returnType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subscriber {
|
||||
var endpoints []*register.Endpoint
|
||||
var handlers []*handler
|
||||
|
||||
options := NewSubscriberOptions(opts...)
|
||||
|
||||
if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func {
|
||||
h := &handler{
|
||||
method: reflect.ValueOf(sub),
|
||||
}
|
||||
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
h.reqType = typ.In(0)
|
||||
case 2:
|
||||
h.ctxType = typ.In(0)
|
||||
h.reqType = typ.In(1)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
ep := ®ister.Endpoint{
|
||||
Name: "Func",
|
||||
Request: register.ExtractSubValue(typ),
|
||||
Metadata: metadata.New(2),
|
||||
}
|
||||
ep.Metadata.Set("topic", topic)
|
||||
ep.Metadata.Set("subscriber", "true")
|
||||
endpoints = append(endpoints, ep)
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
h := &handler{
|
||||
method: method.Func,
|
||||
}
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 2:
|
||||
h.reqType = method.Type.In(1)
|
||||
case 3:
|
||||
h.ctxType = method.Type.In(1)
|
||||
h.reqType = method.Type.In(2)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
ep := ®ister.Endpoint{
|
||||
Name: name + "." + method.Name,
|
||||
Request: register.ExtractSubValue(method.Type),
|
||||
Metadata: metadata.New(2),
|
||||
}
|
||||
ep.Metadata.Set("topic", topic)
|
||||
ep.Metadata.Set("subscriber", "true")
|
||||
endpoints = append(endpoints, ep)
|
||||
}
|
||||
}
|
||||
|
||||
return &subscriber{
|
||||
rcvr: reflect.ValueOf(sub),
|
||||
typ: reflect.TypeOf(sub),
|
||||
topic: topic,
|
||||
subscriber: sub,
|
||||
handlers: handlers,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (n *noopServer) newBatchSubHandler(sb *subscriber, opts Options) broker.BatchHandler {
|
||||
return func(ps broker.Events) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
n.RLock()
|
||||
config := n.opts
|
||||
n.RUnlock()
|
||||
if config.Logger.V(logger.ErrorLevel) {
|
||||
config.Logger.Error(n.opts.Context, "panic recovered: ", r)
|
||||
config.Logger.Error(n.opts.Context, string(debug.Stack()))
|
||||
}
|
||||
err = errors.InternalServerError(n.opts.Name+".subscriber", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
msgs := make([]Message, 0, len(ps))
|
||||
ctxs := make([]context.Context, 0, len(ps))
|
||||
for _, p := range ps {
|
||||
msg := p.Message()
|
||||
// if we don't have headers, create empty map
|
||||
if msg.Header == nil {
|
||||
msg.Header = metadata.New(2)
|
||||
}
|
||||
|
||||
ct, _ := msg.Header.Get(metadata.HeaderContentType)
|
||||
if len(ct) == 0 {
|
||||
msg.Header.Set(metadata.HeaderContentType, defaultContentType)
|
||||
ct = defaultContentType
|
||||
}
|
||||
hdr := metadata.Copy(msg.Header)
|
||||
topic, _ := msg.Header.Get(metadata.HeaderTopic)
|
||||
ctxs = append(ctxs, metadata.NewIncomingContext(sb.opts.Context, hdr))
|
||||
msgs = append(msgs, &rpcMessage{
|
||||
topic: topic,
|
||||
contentType: ct,
|
||||
header: msg.Header,
|
||||
body: msg.Body,
|
||||
})
|
||||
}
|
||||
results := make(chan error, len(sb.handlers))
|
||||
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
handler := sb.handlers[i]
|
||||
|
||||
var req reflect.Value
|
||||
|
||||
switch handler.reqType.Kind() {
|
||||
case reflect.Ptr:
|
||||
req = reflect.New(handler.reqType.Elem())
|
||||
default:
|
||||
req = reflect.New(handler.reqType.Elem()).Elem()
|
||||
}
|
||||
|
||||
reqType := handler.reqType
|
||||
var cf codec.Codec
|
||||
for _, msg := range msgs {
|
||||
cf, err = n.newCodec(msg.ContentType())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rb := reflect.New(req.Type().Elem())
|
||||
if err = cf.ReadBody(bytes.NewReader(msg.(*rpcMessage).body), rb.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.(*rpcMessage).codec = cf
|
||||
msg.(*rpcMessage).payload = rb.Interface()
|
||||
}
|
||||
|
||||
fn := func(ctxs []context.Context, ms []Message) error {
|
||||
var vals []reflect.Value
|
||||
if sb.typ.Kind() != reflect.Func {
|
||||
vals = append(vals, sb.rcvr)
|
||||
}
|
||||
if handler.ctxType != nil {
|
||||
vals = append(vals, reflect.ValueOf(ctxs))
|
||||
}
|
||||
payloads := reflect.MakeSlice(reqType, 0, len(ms))
|
||||
for _, m := range ms {
|
||||
payloads = reflect.Append(payloads, reflect.ValueOf(m.Body()))
|
||||
}
|
||||
vals = append(vals, payloads)
|
||||
|
||||
returnValues := handler.method.Call(vals)
|
||||
if rerr := returnValues[0].Interface(); rerr != nil {
|
||||
return rerr.(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := len(opts.BatchSubWrappers); i > 0; i-- {
|
||||
fn = opts.BatchSubWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
if n.wg != nil {
|
||||
n.wg.Add(1)
|
||||
}
|
||||
go func() {
|
||||
if n.wg != nil {
|
||||
defer n.wg.Done()
|
||||
}
|
||||
results <- fn(ctxs, msgs)
|
||||
}()
|
||||
}
|
||||
|
||||
var errors []string
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
if rerr := <-results; rerr != nil {
|
||||
errors = append(errors, rerr.Error())
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
err = fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (n *noopServer) newSubHandler(sb *subscriber, opts Options) broker.Handler {
|
||||
return func(p broker.Event) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
n.RLock()
|
||||
config := n.opts
|
||||
n.RUnlock()
|
||||
if config.Logger.V(logger.ErrorLevel) {
|
||||
config.Logger.Error(n.opts.Context, "panic recovered: ", r)
|
||||
config.Logger.Error(n.opts.Context, string(debug.Stack()))
|
||||
}
|
||||
err = errors.InternalServerError(n.opts.Name+".subscriber", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
msg := p.Message()
|
||||
// if we don't have headers, create empty map
|
||||
if msg.Header == nil {
|
||||
msg.Header = metadata.New(2)
|
||||
}
|
||||
|
||||
ct := msg.Header["Content-Type"]
|
||||
if len(ct) == 0 {
|
||||
msg.Header.Set(metadata.HeaderContentType, defaultContentType)
|
||||
ct = defaultContentType
|
||||
}
|
||||
cf, err := n.newCodec(ct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hdr := metadata.New(len(msg.Header))
|
||||
for k, v := range msg.Header {
|
||||
if k == "Content-Type" {
|
||||
continue
|
||||
}
|
||||
hdr.Set(k, v)
|
||||
}
|
||||
|
||||
ctx := metadata.NewIncomingContext(sb.opts.Context, hdr)
|
||||
|
||||
results := make(chan error, len(sb.handlers))
|
||||
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
handler := sb.handlers[i]
|
||||
|
||||
var isVal bool
|
||||
var req reflect.Value
|
||||
|
||||
if handler.reqType.Kind() == reflect.Ptr {
|
||||
req = reflect.New(handler.reqType.Elem())
|
||||
} else {
|
||||
req = reflect.New(handler.reqType)
|
||||
isVal = true
|
||||
}
|
||||
if isVal {
|
||||
req = req.Elem()
|
||||
}
|
||||
|
||||
if err = cf.ReadBody(bytes.NewBuffer(msg.Body), req.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fn := func(ctx context.Context, msg Message) error {
|
||||
var vals []reflect.Value
|
||||
if sb.typ.Kind() != reflect.Func {
|
||||
vals = append(vals, sb.rcvr)
|
||||
}
|
||||
if handler.ctxType != nil {
|
||||
vals = append(vals, reflect.ValueOf(ctx))
|
||||
}
|
||||
|
||||
vals = append(vals, reflect.ValueOf(msg.Body()))
|
||||
|
||||
returnValues := handler.method.Call(vals)
|
||||
if rerr := returnValues[0].Interface(); rerr != nil {
|
||||
return rerr.(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := len(opts.SubWrappers); i > 0; i-- {
|
||||
fn = opts.SubWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
if n.wg != nil {
|
||||
n.wg.Add(1)
|
||||
}
|
||||
go func() {
|
||||
if n.wg != nil {
|
||||
defer n.wg.Done()
|
||||
}
|
||||
cerr := fn(ctx, &rpcMessage{
|
||||
topic: sb.topic,
|
||||
contentType: ct,
|
||||
payload: req.Interface(),
|
||||
header: msg.Header,
|
||||
})
|
||||
results <- cerr
|
||||
}()
|
||||
}
|
||||
var errors []string
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
if rerr := <-results; rerr != nil {
|
||||
errors = append(errors, rerr.Error())
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
err = fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (s *subscriber) Topic() string {
|
||||
return s.topic
|
||||
}
|
||||
|
||||
func (s *subscriber) Subscriber() interface{} {
|
||||
return s.subscriber
|
||||
}
|
||||
|
||||
func (s *subscriber) Endpoints() []*register.Endpoint {
|
||||
return s.endpoints
|
||||
}
|
||||
|
||||
func (s *subscriber) Options() SubscriberOptions {
|
||||
return s.opts
|
||||
}
|
@@ -9,25 +9,9 @@ import (
|
||||
// request and response types.
|
||||
type HandlerFunc func(ctx context.Context, req Request, rsp interface{}) error
|
||||
|
||||
// SubscriberFunc represents a single method of a subscriber. It's used primarily
|
||||
// for the wrappers. What's handed to the actual method is the concrete
|
||||
// publication message.
|
||||
type SubscriberFunc func(ctx context.Context, msg Message) error
|
||||
|
||||
// BatchSubscriberFunc represents a single method of a subscriber. It's used primarily
|
||||
// for the wrappers. What's handed to the actual method is the concrete
|
||||
// publication message. This func used by batch subscribers
|
||||
type BatchSubscriberFunc func(ctxs []context.Context, msgs []Message) error
|
||||
|
||||
// HandlerWrapper wraps the HandlerFunc and returns the equivalent
|
||||
type HandlerWrapper func(HandlerFunc) HandlerFunc
|
||||
|
||||
// SubscriberWrapper wraps the SubscriberFunc and returns the equivalent
|
||||
type SubscriberWrapper func(SubscriberFunc) SubscriberFunc
|
||||
|
||||
// BatchSubscriberWrapper wraps the SubscriberFunc and returns the equivalent
|
||||
type BatchSubscriberWrapper func(BatchSubscriberFunc) BatchSubscriberFunc
|
||||
|
||||
// StreamWrapper wraps a Stream interface and returns the equivalent.
|
||||
// Because streams exist for the lifetime of a method invocation this
|
||||
// is a convenient way to wrap a Stream as its in use for trace, monitoring,
|
||||
|
Reference in New Issue
Block a user