@@ -29,6 +29,7 @@ type consumer struct {
2929 groupId string
3030 handlers map [string ]Handler
3131 readTimeout time.Duration
32+ seekTimeout time.Duration
3233 sig chan os.Signal
3334 logsChannel chan kafka.LogEvent
3435 waiting []chan error
@@ -48,6 +49,60 @@ type consumer struct {
4849 }
4950}
5051
52+ // NewConsumer creates a new Kafka consumer with the specified configuration
53+ // and options. The consumer must be started before it can receive messages.
54+ func NewConsumer (config * Config , opts ... ConsumerOption ) (Consumer , error ) {
55+ handle := func (err error ) (Consumer , error ) {
56+ return nil , fmt .Errorf ("kafka.NewConsumer: %w" , err )
57+ }
58+
59+ const defaultReadTimeout = 1 * time .Second
60+ const defaultSeekTimeout = 100 * time .Millisecond
61+
62+ consumer := & consumer {
63+ handlers : map [string ]Handler {},
64+ readTimeout : defaultReadTimeout ,
65+ seekTimeout : defaultSeekTimeout ,
66+ }
67+
68+ // clone the config and apply options
69+ config = config .clone ()
70+ if err := consumer .configure (config , opts ... ); err != nil {
71+ return handle (err )
72+ }
73+
74+ // create the confluent consumer
75+ var err error
76+ if consumer .Consumer , err = createConsumer (& config .config ); err != nil {
77+ return handle (fmt .Errorf ("createConsumer: %w" , err ))
78+ }
79+ consumer .funcs .close = consumer .Consumer .Close
80+ consumer .funcs .commitOffsets = consumer .Consumer .CommitOffsets
81+ consumer .funcs .readMessage = consumer .Consumer .ReadMessage
82+ consumer .funcs .seek = consumer .Consumer .Seek
83+ consumer .funcs .subscribe = consumer .Consumer .SubscribeTopics
84+
85+ // start a go routine to read events from the logs channel to prevent
86+ // it filling up;
87+ consumer .logsChannel = consumer .Consumer .Logs ()
88+ go func () {
89+ for {
90+ if _ , ok := <- consumer .logsChannel ; ! ok {
91+ consumer .logsChannel = nil
92+ return
93+ }
94+ }
95+ }()
96+
97+ // establish a ctrl-c signal channel for running in interactive console
98+ consumer .sig = make (chan os.Signal , 1 )
99+ signal .Notify (consumer .sig , syscall .SIGINT , syscall .SIGTERM )
100+
101+ consumer .setState (csReady )
102+
103+ return consumer , nil
104+ }
105+
51106// commit commits the offset of the specified message.
52107//
53108// If readNext is true, the offset is committed as is (the consumer will read
@@ -59,12 +114,10 @@ type consumer struct {
59114// If the commit fails, a FatalError is returned (the consumer will stop
60115// processing messages)
61116var commitOffset = func (ctx context.Context , c * consumer , msg * kafka.Message , readNext bool ) error {
62- const seekTimeoutMS = 100 // FUTURE: make configurable per consumer?
63-
64117 offset := msg .TopicPartition
65118 if readNext {
66119 offset .Offset += 1
67- } else if err := c .funcs .seek (offset , seekTimeoutMS ); err != nil {
120+ } else if err := c .funcs .seek (offset , int ( c . seekTimeout . Milliseconds ()) ); err != nil {
68121 return fmt .Errorf ("commit: seek: %w" , err )
69122 }
70123
@@ -532,53 +585,3 @@ func (c *consumer) configure(cfg *Config, opts ...ConsumerOption) error {
532585
533586 return nil
534587}
535-
536- // NewConsumer creates a new Kafka consumer with the specified configuration
537- // and options. The consumer must be started before it can receive messages.
538- func NewConsumer (config * Config , opts ... ConsumerOption ) (Consumer , error ) {
539- handle := func (err error ) (Consumer , error ) {
540- return nil , fmt .Errorf ("kafka.NewConsumer: %w" , err )
541- }
542-
543- consumer := & consumer {
544- handlers : map [string ]Handler {},
545- readTimeout : 1 * time .Second ,
546- }
547-
548- // clone the config and apply options
549- config = config .clone ()
550- if err := consumer .configure (config , opts ... ); err != nil {
551- return handle (err )
552- }
553-
554- // create the confluent consumer
555- var err error
556- if consumer .Consumer , err = createConsumer (& config .config ); err != nil {
557- return handle (fmt .Errorf ("createConsumer: %w" , err ))
558- }
559- consumer .funcs .close = consumer .Consumer .Close
560- consumer .funcs .commitOffsets = consumer .Consumer .CommitOffsets
561- consumer .funcs .readMessage = consumer .Consumer .ReadMessage
562- consumer .funcs .seek = consumer .Consumer .Seek
563- consumer .funcs .subscribe = consumer .Consumer .SubscribeTopics
564-
565- // start a go routine to read events from the logs channel to prevent
566- // it filling up;
567- consumer .logsChannel = consumer .Consumer .Logs ()
568- go func () {
569- for {
570- if _ , ok := <- consumer .logsChannel ; ! ok {
571- consumer .logsChannel = nil
572- return
573- }
574- }
575- }()
576-
577- // establish a ctrl-c signal channel for running in interactive console
578- consumer .sig = make (chan os.Signal , 1 )
579- signal .Notify (consumer .sig , syscall .SIGINT , syscall .SIGTERM )
580-
581- consumer .setState (csReady )
582-
583- return consumer , nil
584- }
0 commit comments