2121import java .util .ArrayList ;
2222import java .util .Iterator ;
2323import java .util .List ;
24+ import java .util .concurrent .atomic .AtomicLong ;
2425
2526public class NatsJetStreamPullSubscription extends NatsJetStreamSubscription {
2627
28+ AtomicLong pullId = new AtomicLong ();
29+
2730 NatsJetStreamPullSubscription (String sid , String subject ,
2831 NatsConnection connection , NatsDispatcher dispatcher ,
2932 NatsJetStream js ,
@@ -42,26 +45,32 @@ boolean isPullMode() {
4245 */
4346 @ Override
4447 public void pull (int batchSize ) {
45- pull (PullRequestOptions .builder (batchSize ).build ());
48+ _pull (PullRequestOptions .builder (batchSize ).build ());
4649 }
4750
4851 /**
4952 * {@inheritDoc}
5053 */
5154 @ Override
5255 public void pull (PullRequestOptions pullRequestOptions ) {
56+ _pull (pullRequestOptions );
57+ }
58+
59+ private String _pull (PullRequestOptions pullRequestOptions ) {
5360 String publishSubject = js .prependPrefix (String .format (JSAPI_CONSUMER_MSG_NEXT , stream , consumerName ));
5461 manager .startPullRequest (pullRequestOptions );
55- connection .publish (publishSubject , getSubject (), pullRequestOptions .serialize ());
62+ String pullId = getSubject ().replace ("*" , Long .toString (this .pullId .incrementAndGet ()));
63+ connection .publish (publishSubject , pullId , pullRequestOptions .serialize ());
5664 connection .lenientFlushBuffer ();
65+ return pullId ;
5766 }
5867
5968 /**
6069 * {@inheritDoc}
6170 */
6271 @ Override
6372 public void pullNoWait (int batchSize ) {
64- pull (PullRequestOptions .noWait (batchSize ).build ());
73+ _pull (PullRequestOptions .noWait (batchSize ).build ());
6574 }
6675
6776 /**
@@ -70,7 +79,7 @@ public void pullNoWait(int batchSize) {
7079 @ Override
7180 public void pullNoWait (int batchSize , Duration expiresIn ) {
7281 durationGtZeroRequired (expiresIn , "NoWait Expires In" );
73- pull (PullRequestOptions .noWait (batchSize ).expiresIn (expiresIn ).build ());
82+ _pull (PullRequestOptions .noWait (batchSize ).expiresIn (expiresIn ).build ());
7483 }
7584
7685 /**
@@ -79,7 +88,7 @@ public void pullNoWait(int batchSize, Duration expiresIn) {
7988 @ Override
8089 public void pullNoWait (int batchSize , long expiresInMillis ) {
8190 durationGtZeroRequired (expiresInMillis , "NoWait Expires In" );
82- pull (PullRequestOptions .noWait (batchSize ).expiresIn (expiresInMillis ).build ());
91+ _pull (PullRequestOptions .noWait (batchSize ).expiresIn (expiresInMillis ).build ());
8392 }
8493
8594 /**
@@ -88,7 +97,7 @@ public void pullNoWait(int batchSize, long expiresInMillis) {
8897 @ Override
8998 public void pullExpiresIn (int batchSize , Duration expiresIn ) {
9099 durationGtZeroRequired (expiresIn , "Expires In" );
91- pull (PullRequestOptions .builder (batchSize ).expiresIn (expiresIn ).build ());
100+ _pull (PullRequestOptions .builder (batchSize ).expiresIn (expiresIn ).build ());
92101 }
93102
94103 /**
@@ -97,7 +106,7 @@ public void pullExpiresIn(int batchSize, Duration expiresIn) {
97106 @ Override
98107 public void pullExpiresIn (int batchSize , long expiresInMillis ) {
99108 durationGtZeroRequired (expiresInMillis , "Expires In" );
100- pull (PullRequestOptions .builder (batchSize ).expiresIn (expiresInMillis ).build ());
109+ _pull (PullRequestOptions .builder (batchSize ).expiresIn (expiresInMillis ).build ());
101110 }
102111
103112 /**
@@ -133,7 +142,7 @@ private List<Message> _fetch(int batchSize, long maxWaitMillis) {
133142 maxWaitMillis > MIN_MILLIS
134143 ? maxWaitMillis - EXPIRE_LESS_MILLIS
135144 : maxWaitMillis );
136- pull (PullRequestOptions .builder (batchLeft ).expiresIn (expires ).build ());
145+ String pullId = _pull (PullRequestOptions .builder (batchLeft ).expiresIn (expires ).build ());
137146
138147 // timeout > 0 process as many messages we can in that time period
139148 // If we get a message that either manager handles, we try again, but
@@ -152,9 +161,13 @@ private List<Message> _fetch(int batchSize, long maxWaitMillis) {
152161 break ;
153162 case TERMINUS :
154163 case ERROR :
155- return messages ;
164+ // reply match will be null on pushes, all status are "managed" anyway, so ignored in this loop
165+ // otherwise (pull) if there is a match, the status applies
166+ if (pullId .equals (msg .getSubject ())) {
167+ return messages ;
168+ }
156169 }
157- // case STATUS, try again while we have time
170+ // case pull not match / other ManageResult (i.e. STATUS) , try again while we have time
158171 timeLeftNanos = maxWaitNanos - (System .nanoTime () - start );
159172 }
160173 }
@@ -172,18 +185,13 @@ private List<Message> drainAlreadyBuffered(int batchSize) {
172185 if (msg == null ) {
173186 return messages ; // no more message currently queued
174187 }
175- switch (manager .manage (msg )) {
176- case MESSAGE :
177- messages .add (msg );
178- if (messages .size () == batchSize ) {
179- return messages ;
180- }
181- break ;
182- case TERMINUS :
183- case ERROR :
188+ if (manager .manage (msg ) == MessageManager .ManageResult .MESSAGE ) {
189+ messages .add (msg );
190+ if (messages .size () == batchSize ) {
184191 return messages ;
192+ }
185193 }
186- // case STATUS, we need to try again
194+ // since this is buffered, no non-message applies, try again
187195 }
188196 }
189197 catch (InterruptedException ignore ) {
@@ -242,7 +250,7 @@ public Message next() {
242250 }
243251
244252 // if there were some messages buffered, reduce the raw pull batch size
245- pull (PullRequestOptions .builder (batchLeft ).expiresIn (maxWaitMillis ).build ());
253+ String pullId = _pull (PullRequestOptions .builder (batchLeft ).expiresIn (maxWaitMillis ).build ());
246254
247255 final long timeout = maxWaitMillis ;
248256
@@ -264,7 +272,7 @@ public boolean hasNext() {
264272 }
265273
266274 if (buffered .size () == 0 ) {
267- msg = _nextUnmanaged (timeout );
275+ msg = _nextUnmanaged (timeout , pullId );
268276 if (msg == null ) {
269277 done = true ;
270278 return false ;
0 commit comments