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  }