@@ -2,215 +2,82 @@ package kafka
2
2
3
3
import (
4
4
"context"
5
- "sync"
6
5
7
- cronsumer "github.com/Trendyol/kafka-cronsumer"
8
6
kcronsumer "github.com/Trendyol/kafka-cronsumer/pkg/kafka"
9
7
"github.com/Trendyol/kafka-konsumer/instrumentation"
10
8
"github.com/segmentio/kafka-go"
11
9
)
12
10
13
- type Consumer interface {
14
- Consume ()
15
- WithLogger (logger LoggerInterface )
16
- Stop () error
17
- }
18
-
19
- type subprocess interface {
20
- Start ()
21
- Stop ()
22
- }
23
-
24
11
type consumer struct {
25
- r * kafka.Reader
26
- wg sync.WaitGroup
27
- once sync.Once
28
- messageCh chan Message
29
- quit chan struct {}
30
- concurrency int
31
- cronsumer kcronsumer.Cronsumer
12
+ * base
32
13
33
14
consumeFn func (Message ) error
34
-
35
- retryEnabled bool
36
- retryFn func (message kcronsumer.Message ) error
37
- retryTopic string
38
-
39
- logger LoggerInterface
40
-
41
- cancelFn context.CancelFunc
42
- api API
43
- subprocesses []subprocess
44
15
}
45
16
46
- var _ Consumer = (* consumer )(nil )
47
-
48
- func NewConsumer (cfg * ConsumerConfig ) (Consumer , error ) {
49
- logger := NewZapLogger (cfg .LogLevel )
50
- reader , err := cfg .newKafkaReader ()
17
+ func newSingleConsumer (cfg * ConsumerConfig ) (Consumer , error ) {
18
+ consumerBase , err := newBase (cfg )
51
19
if err != nil {
52
- logger .Errorf ("Error when initializing kafka reader %v" , err )
53
20
return nil , err
54
21
}
55
22
56
23
c := consumer {
57
- messageCh : make (chan Message , cfg .Concurrency ),
58
- quit : make (chan struct {}),
59
- concurrency : cfg .Concurrency ,
60
- consumeFn : cfg .ConsumeFn ,
61
- retryEnabled : cfg .RetryEnabled ,
62
- logger : logger ,
63
- subprocesses : []subprocess {},
64
- r : reader ,
24
+ base : consumerBase ,
25
+ consumeFn : cfg .ConsumeFn ,
65
26
}
66
27
67
28
if cfg .RetryEnabled {
68
- c .logger .Debug ("Konsumer retry enabled mode active!" )
69
- kcronsumerCfg := kcronsumer.Config {
70
- Brokers : cfg .RetryConfiguration .Brokers ,
71
- Consumer : kcronsumer.ConsumerConfig {
72
- GroupID : cfg .Reader .GroupID ,
73
- Topic : cfg .RetryConfiguration .Topic ,
74
- Cron : cfg .RetryConfiguration .StartTimeCron ,
75
- Duration : cfg .RetryConfiguration .WorkDuration ,
76
- Concurrency : cfg .Concurrency ,
77
- MinBytes : cfg .Reader .MinBytes ,
78
- MaxBytes : cfg .Reader .MaxBytes ,
79
- MaxRetry : cfg .RetryConfiguration .MaxRetry ,
80
- MaxWait : cfg .Reader .MaxWait ,
81
- CommitInterval : cfg .Reader .CommitInterval ,
82
- HeartbeatInterval : cfg .Reader .HeartbeatInterval ,
83
- SessionTimeout : cfg .Reader .SessionTimeout ,
84
- RebalanceTimeout : cfg .Reader .RebalanceTimeout ,
85
- StartOffset : kcronsumer .ToStringOffset (cfg .Reader .StartOffset ),
86
- RetentionTime : cfg .Reader .RetentionTime ,
87
- },
88
- LogLevel : "info" ,
89
- }
90
-
91
- if ! cfg .RetryConfiguration .SASL .IsEmpty () {
92
- c .logger .Debug ("Setting cronsumer SASL configurations..." )
93
- kcronsumerCfg .SASL .Enabled = true
94
- kcronsumerCfg .SASL .AuthType = string (cfg .RetryConfiguration .SASL .Type )
95
- kcronsumerCfg .SASL .Username = cfg .RetryConfiguration .SASL .Username
96
- kcronsumerCfg .SASL .Password = cfg .RetryConfiguration .SASL .Password
97
- kcronsumerCfg .SASL .Rack = cfg .RetryConfiguration .Rack
98
- }
99
-
100
- if ! cfg .RetryConfiguration .TLS .IsEmpty () {
101
- c .logger .Debug ("Setting cronsumer TLS configurations..." )
102
- kcronsumerCfg .SASL .RootCAPath = cfg .RetryConfiguration .TLS .RootCAPath
103
- kcronsumerCfg .SASL .IntermediateCAPath = cfg .RetryConfiguration .TLS .IntermediateCAPath
104
- }
105
-
106
- c .retryTopic = cfg .RetryConfiguration .Topic
107
- c .retryFn = func (message kcronsumer.Message ) error {
108
- consumeErr := c .consumeFn (ToMessage (message ))
109
- instrumentation .TotalProcessedRetryableMessagesCounter .Inc ()
110
- return consumeErr
111
- }
112
-
113
- c .cronsumer = cronsumer .New (& kcronsumerCfg , c .retryFn )
114
- c .subprocesses = append (c .subprocesses , c .cronsumer )
29
+ c .base .setupCronsumer (cfg , func (message kcronsumer.Message ) error {
30
+ return c .consumeFn (toMessage (message ))
31
+ })
115
32
}
116
33
117
34
if cfg .APIEnabled {
118
- c .logger .Debug ("Metrics API Enabled!" )
119
- c .api = NewAPI (cfg )
120
- c .subprocesses = append (c .subprocesses , c .api )
35
+ c .base .setupAPI (cfg )
121
36
}
122
37
123
38
return & c , nil
124
39
}
125
40
126
41
func (c * consumer ) Consume () {
127
- go c .startSubprocesses ()
128
-
129
- ctx , cancel := context .WithCancel (context .Background ())
130
- c .cancelFn = cancel
131
-
132
- go c .consume (ctx )
42
+ go c .subprocesses .Start ()
43
+ go c .base .startConsume ()
133
44
134
45
for i := 0 ; i < c .concurrency ; i ++ {
135
46
c .wg .Add (1 )
136
47
go func () {
137
48
defer c .wg .Done ()
138
49
139
50
for message := range c .messageCh {
140
- err := c .consumeFn (message )
141
- instrumentation .TotalProcessedMessagesCounter .Inc ()
142
-
143
- if err != nil && c .retryEnabled {
144
- c .logger .Warnf ("Consume Function Err %s, Message is sending to exception/retry topic %s" , err .Error (), c .retryTopic )
145
-
146
- retryableMsg := message .ToRetryableMessage (c .retryTopic )
147
- if err = c .retryFn (retryableMsg ); err != nil {
148
- if err = c .cronsumer .Produce (retryableMsg ); err != nil {
149
- c .logger .Errorf ("Error producing message %s to exception/retry topic %v" ,
150
- string (retryableMsg .Value ), err .Error ())
151
- }
152
- }
153
- }
154
-
155
- if err = c .r .CommitMessages (context .Background (), kafka .Message (message )); err != nil {
156
- c .logger .Errorf ("Error Committing message %s" , string (message .Value ))
157
- }
51
+ c .process (message )
158
52
}
159
53
}()
160
54
}
161
55
}
162
56
163
- func (c * consumer ) Stop () error {
164
- c .logger .Debug ("Consuming is closing!" )
165
- var err error
166
- c .once .Do (func () {
167
- c .stopSubprocesses ()
168
- c .cancelFn ()
169
- c .quit <- struct {}{}
170
- close (c .messageCh )
171
- c .wg .Wait ()
172
- err = c .r .Close ()
173
- })
174
-
175
- return err
176
- }
57
+ func (c * consumer ) process (message Message ) {
58
+ consumeErr := c .consumeFn (message )
177
59
178
- func (c * consumer ) WithLogger (logger LoggerInterface ) {
179
- c .logger = logger
180
- }
181
-
182
- func (c * consumer ) startSubprocesses () {
183
- for i := range c .subprocesses {
184
- c .subprocesses [i ].Start ()
185
- }
186
- }
60
+ if consumeErr != nil && c .retryEnabled {
61
+ c .logger .Warnf ("Consume Function Err %s, Message will be retried" , consumeErr .Error ())
187
62
188
- func (c * consumer ) stopSubprocesses () {
189
- for i := range c .subprocesses {
190
- c .subprocesses [i ].Stop ()
191
- }
192
- }
63
+ // Try to process same message again
64
+ if consumeErr = c .consumeFn (message ); consumeErr != nil {
65
+ c .logger .Warnf ("Consume Function Again Err %s, message is sending to exception/retry topic %s" , consumeErr .Error (), c .retryTopic )
193
66
194
- func (c * consumer ) consume (ctx context.Context ) {
195
- c .logger .Debug ("Consuming is starting" )
196
- c .wg .Add (1 )
197
- defer c .wg .Done ()
198
-
199
- for {
200
- select {
201
- case <- c .quit :
202
- return
203
- default :
204
- message , err := c .r .FetchMessage (ctx )
205
- if err != nil {
206
- if ctx .Err () != nil {
207
- continue
208
- }
209
- c .logger .Errorf ("Message could not read, err %s" , err .Error ())
210
- continue
67
+ retryableMsg := message .toRetryableMessage (c .retryTopic )
68
+ if produceErr := c .cronsumer .Produce (retryableMsg ); produceErr != nil {
69
+ c .logger .Errorf ("Error producing message %s to exception/retry topic %s" ,
70
+ string (retryableMsg .Value ), produceErr .Error ())
211
71
}
212
-
213
- c .messageCh <- Message (message )
214
72
}
215
73
}
74
+
75
+ commitErr := c .r .CommitMessages (context .Background (), kafka .Message (message ))
76
+ if commitErr != nil {
77
+ instrumentation .TotalUnprocessedMessagesCounter .Inc ()
78
+ c .logger .Errorf ("Error Committing message %s, %s" , string (message .Value ), commitErr .Error ())
79
+ return
80
+ }
81
+
82
+ instrumentation .TotalProcessedMessagesCounter .Inc ()
216
83
}
0 commit comments