2929
3030import javax .annotation .Nullable ;
3131import java .util .Iterator ;
32+ import java .util .NoSuchElementException ;
33+ import java .util .concurrent .atomic .AtomicBoolean ;
3234
3335import static co .elastic .apm .agent .awssdk .common .AbstractSQSInstrumentationHelper .MESSAGE_PROCESSING_ACTION ;
3436import static co .elastic .apm .agent .awssdk .common .AbstractSQSInstrumentationHelper .MESSAGING_TYPE ;
@@ -43,6 +45,7 @@ public abstract class AbstractMessageIteratorWrapper<Message> implements Iterato
4345 private final String queueName ;
4446 private final AbstractSQSInstrumentationHelper <?, ?, Message > sqsInstrumentationHelper ;
4547 private final TextHeaderGetter <Message > textHeaderGetter ;
48+ private final AtomicBoolean iterationEnded ;
4649
4750 public AbstractMessageIteratorWrapper (Iterator <Message > delegate , Tracer tracer ,
4851 String queueName ,
@@ -53,21 +56,25 @@ public AbstractMessageIteratorWrapper(Iterator<Message> delegate, Tracer tracer,
5356 this .queueName = queueName ;
5457 this .sqsInstrumentationHelper = sqsInstrumentationHelper ;
5558 this .textHeaderGetter = textHeaderGetter ;
59+ this .iterationEnded = new AtomicBoolean (false );
5660 }
5761
5862 @ Override
5963 public boolean hasNext () {
60- endCurrentTransaction ();
61- endMessageProcessingSpan ();
62- return delegate .hasNext ();
64+ boolean hasNext = delegate .hasNext ();
65+ if (!hasNext && iterationEnded .compareAndSet (false , true )) {
66+ endCurrentTransaction ();
67+ endMessageProcessingSpan ();
68+ }
69+ return hasNext ;
6370 }
6471
6572 @ Nullable
6673 public Transaction <?> endCurrentTransaction () {
6774 Transaction <?> transaction = null ;
6875 try {
6976 transaction = tracer .currentTransaction ();
70- if (transaction != null && MESSAGING_TYPE .equals (transaction .getType ())) {
77+ if (transaction != null && ! transaction . isFinished () && MESSAGING_TYPE .equals (transaction .getType ())) {
7178 transaction .deactivate ().end ();
7279 return null ;
7380 }
@@ -93,12 +100,21 @@ public void endMessageProcessingSpan() {
93100
94101 @ Override
95102 public Message next () {
96- Transaction <?> currentTransaction = endCurrentTransaction ();
97- Message sqsMessage = delegate .next ();
98- if (currentTransaction == null ) {
99- sqsInstrumentationHelper .startTransactionOnMessage (sqsMessage , queueName , textHeaderGetter );
103+ try {
104+ Transaction <?> currentTransaction = endCurrentTransaction ();
105+ Message sqsMessage = delegate .next ();
106+ if (currentTransaction == null ) {
107+ sqsInstrumentationHelper .startTransactionOnMessage (sqsMessage , queueName , textHeaderGetter );
108+ }
109+ return sqsMessage ;
110+ } catch (NoSuchElementException e ) {
111+ // end the transaction when the caller loops with a try/catch until an exception is thrown
112+ if (iterationEnded .compareAndSet (false , true )) {
113+ endCurrentTransaction ();
114+ endMessageProcessingSpan ();
115+ }
116+ throw e ;
100117 }
101- return sqsMessage ;
102118 }
103119
104120
0 commit comments