github.com/godaddy-x/freego@v1.0.156/amqp/pull.go (about) 1 package rabbitmq 2 3 import ( 4 "fmt" 5 DIC "github.com/godaddy-x/freego/common" 6 "github.com/godaddy-x/freego/utils" 7 "github.com/godaddy-x/freego/zlog" 8 "github.com/streadway/amqp" 9 "sync" 10 "time" 11 ) 12 13 var ( 14 pullMgrs = make(map[string]*PullManager) 15 ) 16 17 type PullManager struct { 18 mu sync.Mutex 19 conf AmqpConfig 20 conn *amqp.Connection 21 receivers []*PullReceiver 22 } 23 24 func (self *PullManager) InitConfig(input ...AmqpConfig) (*PullManager, error) { 25 for _, v := range input { 26 if _, b := pullMgrs[v.DsName]; b { 27 return nil, utils.Error("rabbitmq pull init failed: [", v.DsName, "] exist") 28 } 29 if len(v.DsName) == 0 { 30 v.DsName = DIC.MASTER 31 } 32 pullMgr := &PullManager{ 33 conf: v, 34 receivers: make([]*PullReceiver, 0), 35 } 36 if _, err := pullMgr.Connect(); err != nil { 37 return nil, err 38 } 39 pullMgrs[v.DsName] = pullMgr 40 zlog.Printf("rabbitmq pull service【%s】has been started successful", v.DsName) 41 } 42 return self, nil 43 } 44 45 func (self *PullManager) Client(ds ...string) (*PullManager, error) { 46 dsName := DIC.MASTER 47 if len(ds) > 0 && len(ds[0]) > 0 { 48 dsName = ds[0] 49 } 50 return pullMgrs[dsName], nil 51 } 52 53 func NewPull(ds ...string) (*PullManager, error) { 54 return new(PullManager).Client(ds...) 55 } 56 57 func (self *PullManager) AddPullReceiver(receivers ...*PullReceiver) { 58 for _, v := range receivers { 59 go self.start(v) 60 } 61 } 62 63 func (self *PullManager) start(receiver *PullReceiver) { 64 self.receivers = append(self.receivers, receiver) 65 self.listen(receiver) 66 time.Sleep(100 * time.Millisecond) 67 } 68 69 func (self *PullManager) Connect() (*PullManager, error) { 70 conn, err := ConnectRabbitMQ(self.conf) 71 if err != nil { 72 return nil, err 73 } 74 self.conn = conn 75 return self, nil 76 } 77 78 func (self *PullManager) openChannel() (*amqp.Channel, error) { 79 self.mu.Lock() 80 defer self.mu.Unlock() 81 channel, err := self.conn.Channel() 82 if err != nil { 83 e, b := err.(*amqp.Error) 84 if b && e.Code == 504 { // 重连connection 85 if _, err := self.Connect(); err != nil { 86 return nil, err 87 } 88 } 89 return nil, err 90 } 91 return channel, nil 92 } 93 94 func (self *PullManager) getChannel() *amqp.Channel { 95 index := 0 96 for { 97 if index > 0 { 98 zlog.Warn("rabbitmq pull trying to connect again", 0, zlog.Int("tried", index)) 99 } 100 channel, err := self.openChannel() 101 if err != nil { 102 zlog.Error("rabbitmq pull init Connection/Channel failed", 0, zlog.AddError(err)) 103 time.Sleep(2500 * time.Millisecond) 104 index++ 105 continue 106 } 107 return channel 108 } 109 } 110 111 func (self *PullManager) listen(receiver *PullReceiver) { 112 channel := self.getChannel() 113 receiver.channel = channel 114 exchange := receiver.Config.Option.Exchange 115 queue := receiver.Config.Option.Queue 116 kind := receiver.Config.Option.Kind 117 router := receiver.Config.Option.Router 118 prefetchCount := receiver.Config.PrefetchCount 119 prefetchSize := receiver.Config.PrefetchSize 120 if !utils.CheckInt(receiver.Config.Option.SigTyp, 0, 1) { 121 receiver.Config.Option.SigTyp = 1 122 } 123 if len(receiver.Config.Option.SigKey) < 32 { 124 receiver.Config.Option.SigKey = utils.AddStr(utils.GetLocalSecretKey(), self.conf.SecretKey) 125 } 126 if len(kind) == 0 { 127 kind = direct 128 } 129 if len(router) == 0 { 130 router = queue 131 } 132 if prefetchCount == 0 { 133 prefetchCount = 1 134 } 135 zlog.Println(fmt.Sprintf("rabbitmq pull init queue [%s - %s - %s - %s] successful...", kind, exchange, router, queue)) 136 if err := self.prepareExchange(channel, exchange, kind); err != nil { 137 receiver.OnError(fmt.Errorf("rabbitmq pull init exchange [%s] failed: %s", exchange, err.Error())) 138 return 139 } 140 if err := self.prepareQueue(channel, exchange, queue, router); err != nil { 141 receiver.OnError(fmt.Errorf("rabbitmq pull bind queue [%s] to exchange [%s] failed: %s", queue, exchange, err.Error())) 142 return 143 } 144 if err := channel.Qos(prefetchCount, prefetchSize, false); err != nil { 145 receiver.OnError(fmt.Errorf("rabbitmq pull queue %s qos failed failed: %s", queue, err.Error())) 146 } 147 // 开启消费数据 148 msgs, err := channel.Consume(queue, "", false, false, false, false, nil) 149 if err != nil { 150 receiver.OnError(fmt.Errorf("rabbitmq pull get queue %s failed: %s", queue, err.Error())) 151 } 152 closeChan := make(chan bool, 1) 153 go func(chan<- bool) { 154 mqErr := make(chan *amqp.Error) 155 closeErr := <-channel.NotifyClose(mqErr) 156 zlog.Error("rabbitmq pull connection/channel receive failed", 0, zlog.String("exchange", exchange), zlog.String("queue", queue), zlog.AddError(closeErr)) 157 closeChan <- true 158 }(closeChan) 159 160 go func(<-chan bool) { 161 for { 162 select { 163 case d := <-msgs: 164 for !receiver.OnReceive(d.Body) { 165 delay := receiver.Delay 166 if delay == 0 { 167 delay = 5 168 } 169 time.Sleep(time.Duration(delay) * time.Second) 170 } 171 if err := d.Ack(false); err != nil { 172 zlog.Error("rabbitmq pull received ack failed", 0, zlog.AddError(err)) 173 } 174 case <-closeChan: 175 self.listen(receiver) 176 zlog.Warn("rabbitmq pull received channel exception, successful reconnected", 0, zlog.String("exchange", exchange), zlog.String("queue", queue)) 177 return 178 } 179 } 180 }(closeChan) 181 } 182 183 func (self *PullManager) prepareExchange(channel *amqp.Channel, exchange, kind string) error { 184 return channel.ExchangeDeclare(exchange, kind, true, false, false, false, nil) 185 } 186 187 func (self *PullManager) prepareQueue(channel *amqp.Channel, exchange, queue, router string) error { 188 if _, err := channel.QueueDeclare(queue, true, false, false, false, nil); err != nil { 189 return err 190 } 191 if err := channel.QueueBind(queue, router, exchange, false, nil); err != nil { 192 return err 193 } 194 return nil 195 } 196 197 func (self *PullReceiver) OnError(err error) { 198 zlog.Error("rabbitmq pull receiver data failed", 0, zlog.AddError(err)) 199 } 200 201 type PullReceiver struct { 202 channel *amqp.Channel 203 Config *Config 204 ContentInter func(typ int64) interface{} 205 Callback func(msg *MsgData) error 206 Debug bool // 是否打印具体pull数据实体 207 Delay int // pull失败重试间隔 208 } 209 210 func (self *PullReceiver) OnReceive(b []byte) bool { 211 if b == nil || len(b) == 0 || string(b) == "{}" || string(b) == "[]" { 212 return true 213 } 214 if self.Debug { 215 defer zlog.Debug("rabbitmq pull consumption data monitoring", utils.UnixMilli(), zlog.String("message", utils.Bytes2Str(b))) 216 } 217 msg := &MsgData{} 218 if err := utils.JsonUnmarshal(b, msg); err != nil { 219 zlog.Error("rabbitmq pull consumption data parsing failed", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg), zlog.AddError(err)) 220 } 221 if msg.Content == nil { 222 return true 223 } 224 sigTyp := self.Config.Option.SigTyp 225 sigKey := self.Config.Option.SigKey 226 227 if len(msg.Signature) == 0 { 228 zlog.Error("rabbitmq pull consumption data signature is nil", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg)) 229 return true 230 } 231 v, ok := msg.Content.(string) 232 if !ok { 233 zlog.Error("rabbitmq consumption data (non string type)", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg)) 234 return true 235 } 236 if len(v) == 0 { 237 zlog.Error("rabbitmq consumption data is nil", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg)) 238 return true 239 } 240 if msg.Signature != utils.HMAC_SHA256(utils.AddStr(v, msg.Nonce), sigKey, true) { 241 zlog.Error("rabbitmq consumption data signature invalid", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg)) 242 return true 243 } 244 if sigTyp == 1 { 245 aesContent, err := utils.AesDecrypt(v, sigKey, sigKey) 246 if err != nil { 247 zlog.Error("rabbitmq consumption data aes decrypt failed", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg)) 248 return true 249 } 250 v = utils.Bytes2Str(aesContent) 251 } 252 btv := utils.Base64Decode(v) 253 if btv == nil || len(btv) == 0 { 254 zlog.Error("rabbitmq pull consumption data Base64 parsing failed", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg)) 255 return true 256 } 257 if self.ContentInter == nil { 258 content := map[string]interface{}{} 259 if err := utils.JsonUnmarshal(btv, &content); err != nil { 260 zlog.Error("rabbitmq pull consumption data conversion type(Map) failed", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg), zlog.AddError(err)) 261 return true 262 } 263 msg.Content = content 264 } else { 265 content := self.ContentInter(msg.Type) 266 if err := utils.JsonUnmarshal(btv, content); err != nil { 267 zlog.Error("rabbitmq pull consumption data conversion type(ContentInter) failed", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg), zlog.AddError(err)) 268 return true 269 } 270 msg.Content = content 271 } 272 273 if err := self.Callback(msg); err != nil { 274 if self.Debug { 275 zlog.Error("rabbitmq pull consumption data processing failed", 0, zlog.Any("option", self.Config.Option), zlog.Any("message", msg), zlog.AddError(err)) 276 } else { 277 zlog.Error("rabbitmq pull consumption data processing failed", 0, zlog.Any("option", self.Config.Option), zlog.AddError(err)) 278 } 279 if self.Config.IsNack { 280 return false 281 } 282 } 283 return true 284 }