6464 sendRequestPool * sync.Pool
6565)
6666
67- var errTopicNotFount = "TopicNotFound"
67+ const (
68+ errMsgTopicNotFound = "TopicNotFound"
69+ errMsgTopicTerminated = "TopicTerminatedError"
70+ errMsgProducerBlockedQuotaExceededException = "ProducerBlockedQuotaExceededException"
71+ errMsgProducerFenced = "ProducerFenced"
72+ )
6873
6974func init () {
7075 sendRequestPool = & sync.Pool {
@@ -441,30 +446,28 @@ func (p *partitionProducer) reconnectToBroker() {
441446 }
442447 p .log .WithError (err ).Error ("Failed to create producer at reconnect" )
443448 errMsg := err .Error ()
444- if strings .Contains (errMsg , errTopicNotFount ) {
449+ if strings .Contains (errMsg , errMsgTopicNotFound ) {
445450 // when topic is deleted, we should give up reconnection.
446- p .log .Warn ("Topic Not Found." )
451+ p .log .Warn ("Topic not found, stop reconnecting, close the producer" )
452+ p .doClose (newError (TopicNotFound , err .Error ()))
447453 break
448454 }
449455
450- if strings .Contains (errMsg , "TopicTerminatedError" ) {
451- p .log .Info ("Topic was terminated, failing pending messages, will not reconnect" )
452- pendingItems := p .pendingQueue .ReadableSlice ()
453- for _ , item := range pendingItems {
454- pi := item .(* pendingItem )
455- if pi != nil {
456- pi .Lock ()
457- requests := pi .sendRequests
458- for _ , req := range requests {
459- sr := req .(* sendRequest )
460- if sr != nil {
461- sr .done (nil , newError (TopicTerminated , err .Error ()))
462- }
463- }
464- pi .Unlock ()
465- }
466- }
467- p .setProducerState (producerClosing )
456+ if strings .Contains (errMsg , errMsgTopicTerminated ) {
457+ p .log .Warn ("Topic was terminated, failing pending messages, stop reconnecting, close the producer" )
458+ p .doClose (newError (TopicTerminated , err .Error ()))
459+ break
460+ }
461+
462+ if strings .Contains (errMsg , errMsgProducerBlockedQuotaExceededException ) {
463+ p .log .Warn ("Producer was blocked by quota exceed exception, failing pending messages, stop reconnecting" )
464+ p .failPendingMessages (newError (ProducerBlockedQuotaExceededException , err .Error ()))
465+ break
466+ }
467+
468+ if strings .Contains (errMsg , errMsgProducerFenced ) {
469+ p .log .Warn ("Producer was fenced, failing pending messages, stop reconnecting" )
470+ p .doClose (newError (ProducerFenced , err .Error ()))
468471 break
469472 }
470473
@@ -481,10 +484,18 @@ func (p *partitionProducer) reconnectToBroker() {
481484func (p * partitionProducer ) runEventsLoop () {
482485 for {
483486 select {
484- case data := <- p .dataChan :
487+ case data , ok := <- p .dataChan :
488+ // when doClose() is call, p.dataChan will be closed, data will be nil
489+ if ! ok {
490+ return
491+ }
485492 p .internalSend (data )
486- case i := <- p .cmdChan :
487- switch v := i .(type ) {
493+ case cmd , ok := <- p .cmdChan :
494+ // when doClose() is call, p.dataChan will be closed, cmd will be nil
495+ if ! ok {
496+ return
497+ }
498+ switch v := cmd .(type ) {
488499 case * flushRequest :
489500 p .internalFlush (v )
490501 case * closeProducer :
@@ -1321,13 +1332,18 @@ func (p *partitionProducer) ReceivedSendReceipt(response *pb.CommandSendReceipt)
13211332
13221333func (p * partitionProducer ) internalClose (req * closeProducer ) {
13231334 defer close (req .doneCh )
1335+
1336+ p .doClose (errProducerClosed )
1337+ }
1338+
1339+ func (p * partitionProducer ) doClose (reason error ) {
13241340 if ! p .casProducerState (producerReady , producerClosing ) {
13251341 return
13261342 }
13271343
1344+ p .log .Info ("Closing producer" )
13281345 defer close (p .dataChan )
13291346 defer close (p .cmdChan )
1330- p .log .Info ("Closing producer" )
13311347
13321348 id := p .client .rpcClient .NewRequestID ()
13331349 _ , err := p .client .rpcClient .RequestOnCnx (p ._getConn (), id , pb .BaseCommand_CLOSE_PRODUCER , & pb.CommandCloseProducer {
@@ -1340,7 +1356,7 @@ func (p *partitionProducer) internalClose(req *closeProducer) {
13401356 } else {
13411357 p .log .Info ("Closed producer" )
13421358 }
1343- p .failPendingMessages ()
1359+ p .failPendingMessages (reason )
13441360
13451361 if p .batchBuilder != nil {
13461362 if err = p .batchBuilder .Close (); err != nil {
@@ -1353,7 +1369,7 @@ func (p *partitionProducer) internalClose(req *closeProducer) {
13531369 p .batchFlushTicker .Stop ()
13541370}
13551371
1356- func (p * partitionProducer ) failPendingMessages () {
1372+ func (p * partitionProducer ) failPendingMessages (err error ) {
13571373 curViewItems := p .pendingQueue .ReadableSlice ()
13581374 viewSize := len (curViewItems )
13591375 if viewSize <= 0 {
@@ -1378,11 +1394,11 @@ func (p *partitionProducer) failPendingMessages() {
13781394
13791395 for _ , i := range pi .sendRequests {
13801396 sr := i .(* sendRequest )
1381- sr .done (nil , errProducerClosed )
1397+ sr .done (nil , err )
13821398 }
13831399
13841400 // flag the sending has completed with error, flush make no effect
1385- pi .done (errProducerClosed )
1401+ pi .done (err )
13861402 pi .Unlock ()
13871403
13881404 // finally reached the last view item, current iteration ends
0 commit comments