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 }