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