/
producer.go
145 lines (121 loc) · 3.43 KB
/
producer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
* Author: Tony.Shao
* Email: xiocode@gmail.com
* Github: github.com/xiocode
* File: producer.go
* Description: kafka producer
**/
package kafka
import (
"errors"
"time"
"github.com/Shopify/sarama"
log "github.com/golang/glog"
)
type ProducerErrorCallback func(*sarama.ProducerError)
type Producer struct {
sarama.AsyncProducer
client sarama.Client
config *sarama.Config
callback ProducerErrorCallback
running bool
quit chan bool
done chan bool
}
func NewProducer(brokers []string, name string, config *sarama.Config, cb ProducerErrorCallback) (self *Producer, err error) {
self = &Producer{
callback: cb,
config: config,
quit: make(chan bool),
done: make(chan bool),
}
self.client, err = sarama.NewClient(brokers, nil)
if config == nil {
self.AsyncProducer, err = sarama.NewAsyncProducerFromClient(self.client)
} else {
self.AsyncProducer, err = sarama.NewAsyncProducer(brokers, self.config)
}
if err != nil {
log.Errorf("failed to create producer: %s", err)
return nil, err
}
go self.Start()
return self, nil
}
func NewFastProducer(brokers []string, cb ProducerErrorCallback) (*Producer, error) {
config := sarama.NewConfig()
config.Producer.Return.Successes = false
config.Producer.Compression = sarama.CompressionSnappy
config.Producer.RequiredAcks = sarama.NoResponse
config.Producer.Flush.Messages = 10000
config.Producer.Flush.Frequency = 100 * time.Millisecond
return NewProducer(brokers, "fast", config, cb)
}
func NewSafeProducer(brokers []string) (*Producer, error) {
config := sarama.NewConfig()
config.Producer.Return.Successes = false
config.Producer.Compression = sarama.CompressionSnappy
config.Producer.RequiredAcks = sarama.WaitForAll
config.Producer.Flush.Messages = 10000
config.Producer.Flush.Frequency = 100 * time.Millisecond
config.Producer.Timeout = 100 * time.Millisecond
config.Producer.Retry.Max = 3
return NewProducer(brokers, "safe", config, nil)
}
func NewNormalProducer(brokers []string) (*Producer, error) {
config := sarama.NewConfig()
config.Producer.Return.Successes = false
config.Producer.Compression = sarama.CompressionSnappy
config.Producer.RequiredAcks = sarama.WaitForLocal
config.Producer.Flush.Messages = 10000
config.Producer.Flush.Frequency = 100 * time.Millisecond
config.Producer.Timeout = 100 * time.Millisecond
config.Producer.Retry.Max = 3
return NewProducer(brokers, "normal", config, nil)
}
func (self *Producer) Start() {
if self.config.Producer.Return.Successes == true {
return
}
self.running = true
for {
select {
case err, ok := <-self.Errors():
if ok && self.callback != nil {
self.callback(err)
}
case <-self.quit:
self.running = false
close(self.done)
return
}
}
}
func (self *Producer) Shutdown() {
if self.running {
log.Infof("shutting down producer run loop")
close(self.quit)
log.Infof("waiting for run loop to finish")
<-self.done
}
log.Infof("closing producer")
self.Close()
log.Infof("shutdown done")
}
func (self *Producer) SendMessage(topic, key string, value []byte) (*sarama.ProducerMessage, error) {
if value == nil || len(value) < 1 {
return nil, errors.New("empty message")
}
message := &sarama.ProducerMessage{
Topic: string(topic),
Key: sarama.StringEncoder(key),
Value: sarama.ByteEncoder(value),
}
defer func() {
if err := recover(); err != nil {
log.Error(err)
}
}()
self.Input() <- message
return message, nil
}