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  }