@@ -127,8 +127,6 @@ public class DefaultKafkaProducerFactory<K, V> implements ProducerFactory<K, V>,
127127
128128 private final ThreadLocal <CloseSafeProducer <K , V >> threadBoundProducers = new ThreadLocal <>();
129129
130- private final ThreadLocal <Integer > threadBoundProducerEpochs = new ThreadLocal <>();
131-
132130 private final AtomicInteger epoch = new AtomicInteger ();
133131
134132 private final AtomicInteger clientIdCounter = new AtomicInteger ();
@@ -391,25 +389,21 @@ public Producer<K, V> createProducer(@Nullable String txIdPrefixArg) {
391389 }
392390 if (this .producerPerThread ) {
393391 CloseSafeProducer <K , V > tlProducer = this .threadBoundProducers .get ();
394- if (this .threadBoundProducerEpochs .get () == null ) {
395- this .threadBoundProducerEpochs .set (this .epoch .get ());
396- }
397- if (tlProducer != null && this .epoch .get () != this .threadBoundProducerEpochs .get ()) {
392+ if (tlProducer != null && this .epoch .get () != tlProducer .epoch ) {
398393 closeThreadBoundProducer ();
399394 tlProducer = null ;
400395 }
401396 if (tlProducer == null ) {
402397 tlProducer = new CloseSafeProducer <>(createKafkaProducer (), this ::removeProducer ,
403- this .physicalCloseTimeout );
398+ this .physicalCloseTimeout , this . epoch );
404399 this .threadBoundProducers .set (tlProducer );
405- this .threadBoundProducerEpochs .set (this .epoch .get ());
406400 }
407401 return tlProducer ;
408402 }
409403 synchronized (this ) {
410404 if (this .producer == null ) {
411405 this .producer = new CloseSafeProducer <>(createKafkaProducer (), this ::removeProducer ,
412- this .physicalCloseTimeout );
406+ this .physicalCloseTimeout , this . epoch );
413407 }
414408 return this .producer ;
415409 }
@@ -516,7 +510,8 @@ private CloseSafeProducer<K, V> doCreateTxProducer(String prefix, String suffix,
516510 newProducer = createRawProducer (newProducerConfigs );
517511 newProducer .initTransactions ();
518512 return new CloseSafeProducer <>(newProducer , getCache (prefix ), remover ,
519- (String ) newProducerConfigs .get (ProducerConfig .TRANSACTIONAL_ID_CONFIG ), this .physicalCloseTimeout );
513+ (String ) newProducerConfigs .get (ProducerConfig .TRANSACTIONAL_ID_CONFIG ), this .physicalCloseTimeout ,
514+ this .epoch );
520515 }
521516
522517 protected Producer <K , V > createRawProducer (Map <String , Object > configs ) {
@@ -585,37 +580,57 @@ protected static class CloseSafeProducer<K, V> implements Producer<K, V> {
585580
586581 private final Duration closeTimeout ;
587582
583+ final int epoch ; // NOSONAR
584+
585+ private final AtomicInteger factoryEpoch ;
586+
588587 private volatile Exception producerFailed ;
589588
590589 private volatile boolean closed ;
591590
592591 CloseSafeProducer (Producer <K , V > delegate , Consumer <CloseSafeProducer <K , V >> removeProducer ,
593592 Duration closeTimeout ) {
594593
595- this (delegate , null , removeProducer , null , closeTimeout );
594+ this (delegate , null , removeProducer , null , closeTimeout , new AtomicInteger ());
595+ Assert .isTrue (!(delegate instanceof CloseSafeProducer ), "Cannot double-wrap a producer" );
596+ }
597+
598+ CloseSafeProducer (Producer <K , V > delegate , Consumer <CloseSafeProducer <K , V >> removeProducer ,
599+ Duration closeTimeout , AtomicInteger epoch ) {
600+
601+ this (delegate , null , removeProducer , null , closeTimeout , epoch );
596602 Assert .isTrue (!(delegate instanceof CloseSafeProducer ), "Cannot double-wrap a producer" );
597603 }
598604
599605 CloseSafeProducer (Producer <K , V > delegate , BlockingQueue <CloseSafeProducer <K , V >> cache ,
600606 Duration closeTimeout ) {
601- this (delegate , cache , null , closeTimeout );
607+ this (delegate , cache , null , null , closeTimeout , new AtomicInteger () );
602608 }
603609
604610 CloseSafeProducer (Producer <K , V > delegate , BlockingQueue <CloseSafeProducer <K , V >> cache ,
605611 @ Nullable Consumer <CloseSafeProducer <K , V >> removeConsumerProducer , Duration closeTimeout ) {
606612
607- this (delegate , cache , removeConsumerProducer , null , closeTimeout );
613+ this (delegate , cache , removeConsumerProducer , null , closeTimeout , new AtomicInteger () );
608614 }
609615
610616 CloseSafeProducer (Producer <K , V > delegate , BlockingQueue <CloseSafeProducer <K , V >> cache ,
611617 @ Nullable Consumer <CloseSafeProducer <K , V >> removeProducer , @ Nullable String txId ,
612618 Duration closeTimeout ) {
613619
620+ this (delegate , cache , removeProducer , txId , closeTimeout , new AtomicInteger ());
621+ }
622+
623+ CloseSafeProducer (Producer <K , V > delegate , BlockingQueue <CloseSafeProducer <K , V >> cache ,
624+ @ Nullable Consumer <CloseSafeProducer <K , V >> removeProducer , @ Nullable String txId ,
625+ Duration closeTimeout , AtomicInteger epoch ) {
626+
614627 this .delegate = delegate ;
615628 this .cache = cache ;
616629 this .removeProducer = removeProducer ;
617630 this .txId = txId ;
618631 this .closeTimeout = closeTimeout ;
632+ this .epoch = epoch .get ();
633+ this .factoryEpoch = epoch ;
619634 LOGGER .debug (() -> "Created new Producer: " + this );
620635 }
621636
@@ -749,8 +764,8 @@ public void close(@Nullable Duration timeout) {
749764 else {
750765 if (this .cache != null && this .removeProducer == null ) { // dedicated consumer producers are not cached
751766 synchronized (this ) {
752- if (! this .cache . contains ( this )
753- && !this .cache .offer (this )) {
767+ if (this . epoch != this .factoryEpoch . get ( )
768+ || (! this . cache . contains ( this ) && !this .cache .offer (this ) )) {
754769 this .closed = true ;
755770 this .delegate .close (timeout );
756771 }
0 commit comments