github.com/qxnw/lib4go@v0.0.0-20180426074627-c80c7e84b925/mq/xmq/xmq.producer.go (about) 1 package xmq 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "sync" 8 "time" 9 10 "github.com/qxnw/lib4go/concurrent/cmap" 11 "github.com/qxnw/lib4go/encoding" 12 "github.com/qxnw/lib4go/logger" 13 "github.com/qxnw/lib4go/mq" 14 ) 15 16 //XMQProducer Producer 17 type XMQProducer struct { 18 address string 19 conn net.Conn 20 messages chan *mq.ProcuderMessage 21 backupMsg chan *mq.ProcuderMessage 22 queues cmap.ConcurrentMap 23 connecting bool 24 isConnected bool 25 closeCh chan struct{} 26 done bool 27 lk sync.Mutex 28 writeLock sync.Mutex 29 header []string 30 lastWrite time.Time 31 *mq.OptionConf 32 } 33 34 //NewXMQProducer 创建新的producer 35 func NewXMQProducer(address string, opts ...mq.Option) (producer *XMQProducer, err error) { 36 producer = &XMQProducer{address: address} 37 producer.OptionConf = &mq.OptionConf{} 38 producer.messages = make(chan *mq.ProcuderMessage, 10000) 39 producer.backupMsg = make(chan *mq.ProcuderMessage, 100) 40 producer.closeCh = make(chan struct{}) 41 for _, opt := range opts { 42 opt(producer.OptionConf) 43 } 44 if producer.Logger == nil { 45 producer.Logger = logger.GetSession("xmq.producer", logger.CreateSession()) 46 } 47 producer.header = make([]string, 0, 4) 48 return 49 } 50 51 //Connect 循环连接服务器 52 func (producer *XMQProducer) Connect() error { 53 err := producer.connectOnce() 54 if err != nil { 55 producer.Logger.Error(err) 56 } 57 go func() { 58 START: 59 for { 60 select { 61 case <-producer.closeCh: 62 break START 63 case <-time.After(time.Second * 3): 64 if producer.isConnected { 65 if time.Since(producer.lastWrite).Seconds() > 3 { 66 message, err := NewXMQHeartBit().MakeMessage() 67 if err != nil { 68 producer.Logger.Error(err) 69 continue 70 } 71 err = producer.writeMessage(message) 72 if err == nil { 73 continue 74 } 75 producer.Logger.Error(err) 76 err = producer.connectOnce() 77 if err != nil { 78 producer.Logger.Error(err) 79 } 80 } 81 continue 82 } 83 err = producer.connectOnce() 84 if err != nil { 85 producer.Logger.Error(err) 86 } 87 88 } 89 } 90 }() 91 return nil 92 } 93 94 func (producer *XMQProducer) writeMessage(msg string) error { 95 if !producer.isConnected { 96 return fmt.Errorf("未连接到服务器") 97 } 98 producer.writeLock.Lock() 99 producer.lastWrite = time.Now() 100 result, err := encoding.ConvertBytes([]byte(msg), "gbk") 101 if err != nil { 102 return err 103 } 104 _, err = producer.conn.Write(result) 105 producer.lastWrite = time.Now() 106 producer.writeLock.Unlock() 107 return err 108 } 109 110 //sendLoop 循环发送消息 111 func (producer *XMQProducer) sendLoop() { 112 if producer.done { 113 producer.disconnect() 114 return 115 } 116 if producer.Retry { 117 Loop1: 118 for { 119 select { 120 case msg, ok := <-producer.messages: 121 if !ok { 122 break Loop1 123 } 124 msg.AddSendTimes() 125 if msg.SendTimes > 3 { 126 producer.Logger.Errorf("发送消息失败,丢弃消息(%s)(消息3次未发送成功)", msg.Queue) 127 } 128 //producer.Logger.Debug("发送消息...", msg.Data) 129 err := producer.writeMessage(msg.Data) 130 if err != nil { 131 producer.Logger.Errorf("发送消息失败,稍后重新发送(%s)(err:%v)", msg.Queue, err) 132 select { 133 case producer.messages <- msg: 134 default: 135 producer.Logger.Errorf("发送失败,队列已满无法再次发送(%s):%s", msg.Queue, msg.Data) 136 } 137 break Loop1 138 } 139 } 140 } 141 } else { 142 Loop2: 143 for { 144 select { 145 case msg, ok := <-producer.messages: 146 if !ok { 147 break Loop2 148 } 149 msg.AddSendTimes() 150 //producer.Logger.Debug("发送消息...", msg.Data) 151 err := producer.writeMessage(msg.Data) 152 if err != nil { 153 producer.Logger.Errorf("发送消息失败,放入备份队列(%s)(err:%v)", msg.Queue, err) 154 select { 155 case producer.backupMsg <- msg: 156 default: 157 producer.Logger.Errorf("备份队列已满,无法放入队列(%s):%s", msg.Queue, msg.Data) 158 } 159 break Loop2 160 } 161 } 162 } 163 } 164 if producer.done { //关闭连接 165 producer.disconnect() 166 return 167 } 168 producer.reconnect() 169 } 170 func (producer *XMQProducer) disconnect() { 171 producer.isConnected = false 172 if producer.conn == nil { 173 return 174 } 175 producer.conn.Close() 176 return 177 } 178 179 //GetBackupMessage 获取备份数据 180 func (producer *XMQProducer) GetBackupMessage() chan *mq.ProcuderMessage { 181 return producer.backupMsg 182 } 183 184 //reconnect 自动重连 185 func (producer *XMQProducer) reconnect() { 186 producer.conn.Close() 187 producer.isConnected = false 188 err := producer.Connect() 189 if err != nil { 190 producer.Logger.Errorf("连接到MQ服务器失败:%v", err) 191 } 192 } 193 194 //ConnectOnce 连接到服务器 195 func (producer *XMQProducer) connectOnce() (err error) { 196 if producer.connecting { 197 return nil 198 } 199 producer.lk.Lock() 200 defer producer.lk.Unlock() 201 if producer.connecting { 202 return nil 203 } 204 producer.connecting = true 205 defer func() { 206 producer.connecting = false 207 }() 208 producer.Logger.Infof("连接到服务器:%s", producer.address) 209 producer.conn, err = net.DialTimeout("tcp", producer.address, time.Second*2) 210 if err != nil { 211 return fmt.Errorf("mq 无法连接到远程服务器:%v", err) 212 } 213 producer.isConnected = true 214 producer.lastWrite = time.Now() 215 go producer.sendLoop() 216 return nil 217 } 218 219 //Send 发送消息 220 func (producer *XMQProducer) Send(queue string, msg string, timeout time.Duration) (err error) { 221 if producer.done { 222 return errors.New("mq producer 已关闭") 223 } 224 if !producer.connecting && producer.Retry { 225 return fmt.Errorf("producer无法连接到MQ服务器:%s", producer.address) 226 } 227 message := NewXMQMessage(queue, msg, int(timeout/time.Second)) 228 if producer.OptionConf.Key != "" { 229 message.signKey = producer.OptionConf.Key 230 } 231 smessage, err := message.MakeMessage() 232 if err != nil { 233 return 234 } 235 pm := &mq.ProcuderMessage{Queue: queue, Data: smessage, Timeout: timeout} 236 select { 237 case producer.messages <- pm: 238 return nil 239 default: 240 return errors.New("producer无法连接到MQ服务器,消息队列已满无法发送") 241 } 242 } 243 244 //Close 关闭当前连接 245 func (producer *XMQProducer) Close() { 246 producer.done = true 247 close(producer.closeCh) 248 close(producer.messages) 249 close(producer.backupMsg) 250 } 251 252 type xmqProducerResolver struct { 253 } 254 255 func (s *xmqProducerResolver) Resolve(address string, opts ...mq.Option) (mq.MQProducer, error) { 256 return NewXMQProducer(address, opts...) 257 } 258 func init() { 259 mq.RegisterProducer("xmq", &xmqProducerResolver{}) 260 }