github.com/aaabigfish/gopkg@v1.1.0/mq/nsq/pub.go (about)

     1  package nsq
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/nsqio/go-nsq"
    11  )
    12  
    13  type Producer = nsq.Producer
    14  
    15  var NsqPublisher = &nsq.Producer{}
    16  
    17  type Writer interface {
    18  	Push(data interface{}, key ...[]byte) error
    19  	PushTopic(topic string, data interface{}, key ...[]byte) error
    20  	PushMessage(msg *Message) error
    21  	Publish(topic string, body []byte, key ...[]byte) error
    22  	MultiPublish(topic string, bodys [][]byte, key ...[]byte) error
    23  	PublishDelay(topic string, t time.Duration, body []byte, key ...[]byte) error
    24  	GetProducer() *Producer
    25  	Close()
    26  }
    27  
    28  type producer struct {
    29  	id        int       // 生产者id
    30  	pub       *Producer // 生产者
    31  	unPubFunc func()    // 解除函数
    32  }
    33  
    34  type writer struct {
    35  	c         *Config
    36  	topic     string
    37  	addrs     []string
    38  	mu        sync.RWMutex
    39  	producers []*producer
    40  	balancer  Balancer
    41  }
    42  
    43  // 创建生产者
    44  func NewProducer(addr string, c ...*Config) Writer {
    45  	cfg := &Config{}
    46  	if len(c) > 0 {
    47  		cfg = c[0]
    48  	} else {
    49  		cfg = NewConfig()
    50  	}
    51  
    52  	producer, err := nsq.NewProducer(addr, cfg.NsqConfig)
    53  	if err != nil {
    54  		panic(fmt.Sprintf("new nsq producer failed err(%v)", err))
    55  	}
    56  
    57  	w := &writer{
    58  		addrs: []string{addr},
    59  		c:     cfg,
    60  		topic: cfg.topic,
    61  	}
    62  	w.addProducer(producer)
    63  
    64  	return w
    65  }
    66  
    67  // 创建生产者链接池
    68  // balancer 平衡器,在nsq集群上将消息路由到可用节点的逻辑,详见balancer.go
    69  func NewProducerPool(addrs []string, balancer Balancer, c ...*Config) Writer {
    70  	if len(addrs) == 0 {
    71  		panic("addrs should not be empty")
    72  	}
    73  
    74  	cfg := &Config{}
    75  	if len(c) > 0 {
    76  		cfg = c[0]
    77  	} else {
    78  		cfg = NewConfig()
    79  	}
    80  
    81  	w := &writer{
    82  		addrs: addrs,
    83  		c:     cfg,
    84  		topic: cfg.topic,
    85  	}
    86  
    87  	for _, addr := range addrs {
    88  		p, err := nsq.NewProducer(addr, cfg.NsqConfig)
    89  		if err != nil {
    90  			panic(fmt.Sprintf("new nsq producer failed err(%v)", err))
    91  		}
    92  		w.addProducer(p)
    93  	}
    94  
    95  	if balancer != nil {
    96  		w.balancer = balancer
    97  	} else {
    98  		w.balancer = &RoundRobin{}
    99  	}
   100  
   101  	return w
   102  }
   103  
   104  // 获取生产者实例
   105  func (w *writer) GetProducer() *Producer {
   106  	producer, _ := w.getProducer()
   107  	if producer != nil {
   108  		return nil
   109  	}
   110  	return producer.pub
   111  }
   112  
   113  // 获取平衡器,默认是循环所有节点
   114  func (w *writer) getBalancer() Balancer {
   115  	if w.balancer != nil {
   116  		return w.balancer
   117  	}
   118  	return &RoundRobin{}
   119  }
   120  
   121  func (w *writer) addProducer(p *nsq.Producer) {
   122  	w.mu.Lock()
   123  	defer w.mu.Unlock()
   124  
   125  	producer := &producer{
   126  		pub: p,
   127  	}
   128  
   129  	producer.unPubFunc = func() {
   130  		w.mu.Lock()
   131  		defer w.mu.Unlock()
   132  		for i, pub := range w.producers {
   133  			if pub == producer {
   134  				if pub.pub != nil {
   135  					pub.pub.Stop()
   136  				}
   137  				w.producers = append(w.producers[:i], w.producers[i+1:]...)
   138  				return
   139  			}
   140  		}
   141  	}
   142  
   143  	w.producers = append(w.producers, producer)
   144  }
   145  
   146  func (w *writer) getProducer(key ...[]byte) (*producer, error) {
   147  	w.mu.Lock()
   148  	defer w.mu.Unlock()
   149  
   150  	producersLen := len(w.producers)
   151  	if producersLen <= 0 {
   152  		return nil, errors.New("producers is empty")
   153  	}
   154  	if producersLen == 1 {
   155  		if w.producers[0] == nil || w.producers[0].pub == nil {
   156  			return nil, errors.New("producer is empty")
   157  		}
   158  		return w.producers[0], nil
   159  	}
   160  
   161  	var k []byte
   162  	if len(key) > 0 {
   163  		k = key[0]
   164  	}
   165  	producer := w.producers[w.getBalancer().Balance(k, loadCachedNodes(producersLen)...)]
   166  	if producer == nil || producer.pub == nil {
   167  		return nil, errors.New("producer is empty")
   168  	}
   169  
   170  	return producer, nil
   171  }
   172  
   173  // 发送消息(需要通过NewTopicProducer)
   174  func (w *writer) Push(data interface{}, key ...[]byte) error {
   175  	if w.topic == "" {
   176  		return errors.New("topic is empty")
   177  	}
   178  
   179  	payload, err := json.Marshal(data)
   180  	if err != nil {
   181  		return err
   182  	}
   183  
   184  	return w.Publish(w.topic, payload, key...)
   185  }
   186  
   187  // 发送data到topic
   188  func (w *writer) PushTopic(topic string, data interface{}, key ...[]byte) error {
   189  	payload, err := json.Marshal(data)
   190  	if err != nil {
   191  		return err
   192  	}
   193  	return w.Publish(topic, payload, key...)
   194  }
   195  
   196  // 发送消息
   197  func (w *writer) Publish(topic string, body []byte, key ...[]byte) error {
   198  	producer, err := w.getProducer(key...)
   199  	if err != nil {
   200  		return err
   201  	}
   202  
   203  	if err := producer.pub.Publish(topic, body); err != nil {
   204  		producer.unPubFunc()
   205  		return err
   206  	}
   207  	return nil
   208  }
   209  
   210  // 批量发送消息
   211  func (w *writer) MultiPublish(topic string, bodys [][]byte, key ...[]byte) error {
   212  	producer, err := w.getProducer(key...)
   213  	if err != nil {
   214  		return err
   215  	}
   216  
   217  	if err := producer.pub.MultiPublish(topic, bodys); err != nil {
   218  		producer.unPubFunc()
   219  		return err
   220  	}
   221  	return nil
   222  }
   223  
   224  // 发送异常消息
   225  func (w *writer) PublishDelay(topic string, t time.Duration, body []byte, key ...[]byte) error {
   226  	producer, err := w.getProducer(key...)
   227  	if err != nil {
   228  		return err
   229  	}
   230  	if err := producer.pub.DeferredPublish(topic, t, body); err != nil {
   231  		producer.unPubFunc()
   232  		return err
   233  	}
   234  	return nil
   235  }
   236  
   237  func (w *writer) PushMessage(msg *Message) error {
   238  	if w.topic == "" && msg.Topic == "" {
   239  		return errors.New("topic is empty")
   240  	}
   241  	topic := w.topic
   242  	if msg.Topic != "" {
   243  		topic = msg.Topic
   244  	}
   245  
   246  	if msg.Time <= 0 {
   247  		msg.Time = time.Now().UnixNano()
   248  	}
   249  
   250  	payload, err := json.Marshal(msg)
   251  	if err != nil {
   252  		return err
   253  	}
   254  
   255  	return w.Publish(topic, payload, msg.Key)
   256  }
   257  
   258  func (w *writer) Close() {
   259  	for _, p := range w.producers {
   260  		p.unPubFunc()
   261  	}
   262  
   263  	return
   264  }