Skip to content

Commit 73c6039

Browse files
authored
pull status handling (#819)
1 parent 443968f commit 73c6039

35 files changed

+2291
-1398
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ repositories {
3838
dependencies {
3939
implementation 'net.i2p.crypto:eddsa:0.3.0'
4040
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.0'
41-
testImplementation 'io.nats:jnats-server-runner:1.2.1'
41+
testImplementation 'io.nats:jnats-server-runner:1.2.5'
4242
testImplementation 'nl.jqno.equalsverifier:equalsverifier:3.12.3'
4343
}
4444

src/examples/java/io/nats/examples/ExampleUtils.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package io.nats.examples;
1515

1616
import io.nats.client.*;
17+
import io.nats.client.impl.ErrorListenerLoggerImpl;
1718

1819
import java.time.Duration;
1920
import java.util.concurrent.ThreadLocalRandom;
@@ -31,19 +32,7 @@ public static String getServer(String[] args) {
3132

3233
public static final ConnectionListener EXAMPLE_CONNECTION_LISTENER = (conn, type) -> System.out.println("Status change "+ type);
3334

34-
public static final ErrorListener EXAMPLE_ERROR_LISTENER = new ErrorListener() {
35-
public void exceptionOccurred(Connection conn, Exception exp) {
36-
System.out.println("Exception " + exp.getMessage());
37-
}
38-
39-
public void errorOccurred(Connection conn, String type) {
40-
System.out.println("Error " + type);
41-
}
42-
43-
public void slowConsumerDetected(Connection conn, Consumer consumer) {
44-
System.out.println("Slow consumer");
45-
}
46-
};
35+
public static final ErrorListener EXAMPLE_ERROR_LISTENER = new ErrorListenerLoggerImpl();
4736

4837
public static Options createExampleOptions(String[] args) throws Exception {
4938
String server = getServer(args);

src/examples/java/io/nats/examples/jetstream/NatsJsUtils.java

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.nats.client.api.StorageType;
1919
import io.nats.client.api.StreamConfiguration;
2020
import io.nats.client.api.StreamInfo;
21+
import io.nats.client.impl.NatsJetStreamMetaData;
2122
import io.nats.client.impl.NatsMessage;
2223

2324
import java.io.IOException;
@@ -178,8 +179,16 @@ public static void publish(JetStream js, String subject, int count) throws IOExc
178179
publish(js, subject, "data", count, -1, false);
179180
}
180181

182+
public static void publish(JetStream js, String subject, int count, int msgSize) throws IOException, JetStreamApiException {
183+
publish(js, subject, "data", count, msgSize, false);
184+
}
185+
181186
public static void publish(JetStream js, String subject, String prefix, int count) throws IOException, JetStreamApiException {
182-
publish(js, subject, prefix, count, -1, true);
187+
publish(js, subject, prefix, count, -1, false);
188+
}
189+
190+
public static void publish(JetStream js, String subject, String prefix, int count, int msgSize) throws IOException, JetStreamApiException {
191+
publish(js, subject, prefix, count, msgSize, false);
183192
}
184193

185194
public static void publish(JetStream js, String subject, String prefix, int count, boolean verbose) throws IOException, JetStreamApiException {
@@ -205,7 +214,11 @@ public static void publish(JetStream js, String subject, String prefix, int coun
205214
}
206215

207216
public static byte[] makeData(String prefix, int msgSize, boolean verbose, int x) {
208-
String text = prefix + "#" + x + "#";
217+
if (msgSize == 0) {
218+
return null;
219+
}
220+
221+
String text = prefix + "-" + x + ".";
209222
if (verbose) {
210223
System.out.print(" " + text);
211224
}
@@ -342,6 +355,17 @@ public static void printObject(Object o, String... subObjectNames) {
342355
System.out.println(s);
343356
}
344357

358+
public static String metaString(NatsJetStreamMetaData meta) {
359+
return "Meta{" +
360+
"str='" + meta.getStream() + '\'' +
361+
", con='" + meta.getConsumer() + '\'' +
362+
", delivered=" + meta.deliveredCount() +
363+
", strSeq=" + meta.streamSequence() +
364+
", conSeq=" + meta.consumerSequence() +
365+
", pending=" + meta.pendingCount() +
366+
'}';
367+
}
368+
345369
// ----------------------------------------------------------------------------------------------------
346370
// REPORT
347371
// ----------------------------------------------------------------------------------------------------
@@ -385,4 +409,32 @@ public static int count408s(List<Message> messages) {
385409
}
386410
return count;
387411
}
412+
413+
public static void createCleanMemStream(JetStreamManagement jsm, String stream, String... subs) throws IOException, JetStreamApiException {
414+
try {
415+
jsm.deleteStream(stream);
416+
}
417+
catch (Exception ignore) {}
418+
419+
StreamConfiguration sc = StreamConfiguration.builder()
420+
.name(stream)
421+
.storageType(StorageType.Memory)
422+
.subjects(subs)
423+
.build();
424+
jsm.addStream(sc);
425+
}
426+
427+
public static void createCleanFileStream(JetStreamManagement jsm, String stream, String... subs) throws IOException, JetStreamApiException {
428+
try {
429+
jsm.deleteStream(stream);
430+
}
431+
catch (Exception ignore) {}
432+
433+
StreamConfiguration sc = StreamConfiguration.builder()
434+
.name(stream)
435+
.storageType(StorageType.File)
436+
.subjects(subs)
437+
.build();
438+
jsm.addStream(sc);
439+
}
388440
}

src/main/java/io/nats/client/ErrorListener.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,33 @@ default void heartbeatAlarm(Connection conn, JetStreamSubscription sub,
9191
long lastStreamSequence, long lastConsumerSequence) {}
9292

9393
/**
94-
* Called by the connection when an unhandled status is received.
95-
*
94+
* Called when an unhandled status is received in a push subscription.
9695
* @param conn The connection that had the issue
9796
* @param sub the JetStreamSubscription that this occurred on
9897
* @param status the status
9998
*/
10099
default void unhandledStatus(Connection conn, JetStreamSubscription sub, Status status) {}
101100

101+
/**
102+
* Called when a pull subscription receives a status message that indicates either
103+
* the subscription or pull might be problematic
104+
*
105+
* @param conn The connection that had the issue
106+
* @param sub the JetStreamSubscription that this occurred on
107+
* @param status the status
108+
*/
109+
default void pullStatusWarning(Connection conn, JetStreamSubscription sub, Status status) {}
110+
111+
/**
112+
* Called when a pull subscription receives a status message that indicates either
113+
* the subscription cannot continue or the pull request cannot be processed.
114+
*
115+
* @param conn The connection that had the issue
116+
* @param sub the JetStreamSubscription that this occurred on
117+
* @param status the status
118+
*/
119+
default void pullStatusError(Connection conn, JetStreamSubscription sub, Status status) {}
120+
102121
enum FlowControlSource { FLOW_CONTROL, HEARTBEAT }
103122

104123
/**

src/main/java/io/nats/client/JetStreamStatusException.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,31 @@
1919
* JetStreamStatusException is used to indicate an unknown status message was received.
2020
*/
2121
public class JetStreamStatusException extends IllegalStateException {
22+
public static final String DEFAULT_DESCRIPTION = "Unknown or unprocessed status message";
23+
2224
private final JetStreamSubscription sub;
25+
private final String description;
2326
private final Status status;
2427

2528
/**
2629
* Construct an exception with a status message
27-
*
2830
* @param sub the subscription
2931
* @param status the status
3032
*/
3133
public JetStreamStatusException(JetStreamSubscription sub, Status status) {
32-
super("Unknown or unprocessed status message: " + status.getMessage());
34+
this(sub, DEFAULT_DESCRIPTION, status);
35+
}
36+
37+
/**
38+
* Construct an exception with a status message
39+
* @param sub the subscription
40+
* @param description custom description
41+
* @param status the status
42+
*/
43+
public JetStreamStatusException(JetStreamSubscription sub, String description, Status status) {
44+
super(description + ": " + status.getMessage());
3345
this.sub = sub;
46+
this.description = description;
3447
this.status = status;
3548
}
3649

@@ -43,6 +56,14 @@ public JetStreamSubscription getSubscription() {
4356
return sub;
4457
}
4558

59+
/**
60+
* Get the description
61+
* @return the description
62+
*/
63+
public String getDescription() {
64+
return description;
65+
}
66+
4667
/**
4768
* Get the full status object
4869
*

src/main/java/io/nats/client/JetStreamSubscription.java

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package io.nats.client;
1515

1616
import io.nats.client.api.ConsumerInfo;
17+
import io.nats.client.support.PullStatus;
1718

1819
import java.io.IOException;
1920
import java.time.Duration;
@@ -27,9 +28,8 @@ public interface JetStreamSubscription extends Subscription {
2728

2829
/**
2930
* Initiate pull with the specified batch size.
30-
*
3131
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
32-
* ! Primitive API for Advanced use only. Prefer Fetch or Iterate
32+
* ! Primitive API for ADVANCED use only, officially not supported. Prefer fetch, iterate or reader.
3333
*
3434
* @param batchSize the size of the batch
3535
* @throws IllegalStateException if not a pull subscription.
@@ -38,11 +38,8 @@ public interface JetStreamSubscription extends Subscription {
3838

3939
/**
4040
* Initiate pull with the specified request options
41-
*
4241
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
43-
* ! Primitive API for Advanced use only. Prefer Fetch or Iterate
44-
*
45-
* IMPORTANT! PullRequestOptions ARE CURRENTLY EXPERIMENTAL AND SUBJECT TO CHANGE.
42+
* ! Primitive API for ADVANCED use only, officially not supported. Prefer fetch, iterate or reader.
4643
*
4744
* @param pullRequestOptions the options object
4845
* @throws IllegalStateException if not a pull subscription.
@@ -53,7 +50,7 @@ public interface JetStreamSubscription extends Subscription {
5350
* Initiate pull in noWait mode with the specified batch size.
5451
*
5552
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
56-
* ! Primitive API for Advanced use only. Prefer Fetch or Iterate
53+
* ! Primitive API for ADVANCED use only, officially not supported. Prefer fetch, iterate or reader.
5754
*
5855
* @param batchSize the size of the batch
5956
* @throws IllegalStateException if not a pull subscription.
@@ -62,9 +59,8 @@ public interface JetStreamSubscription extends Subscription {
6259

6360
/**
6461
* Initiate pull in noWait mode with the specified batch size.
65-
*
6662
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
67-
* ! Primitive API for Advanced use only. Prefer Fetch or Iterate
63+
* ! Primitive API for ADVANCED use only, officially not supported. Prefer fetch, iterate or reader.
6864
*
6965
* @param batchSize the size of the batch
7066
* @param expiresIn how long from now this request should be expired from the server wait list
@@ -74,9 +70,8 @@ public interface JetStreamSubscription extends Subscription {
7470

7571
/**
7672
* Initiate pull in noWait mode with the specified batch size.
77-
*
7873
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
79-
* ! Primitive API for Advanced use only. Prefer Fetch or Iterate
74+
* ! Primitive API for ADVANCED use only, officially not supported. Prefer fetch, iterate or reader.
8075
*
8176
* @param batchSize the size of the batch
8277
* @param expiresInMillis how long from now this request should be expired from the server wait list, in milliseconds
@@ -89,13 +84,12 @@ public interface JetStreamSubscription extends Subscription {
8984
* <p>
9085
* <code>sub.nextMessage(timeout)</code> can return a:
9186
* <ul>
92-
* <li>regular message
87+
* <li>regular JetStream message
9388
* <li>null
9489
* </ul>
9590
* <p>
96-
*
9791
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
98-
* ! Primitive API for Advanced use only. Prefer Fetch or Iterate
92+
* ! Primitive API for ADVANCED use only, officially not supported. Prefer fetch, iterate or reader.
9993
*
10094
* @param batchSize the size of the batch
10195
* @param expiresIn how long from now this request should be expired from the server wait list
@@ -109,13 +103,12 @@ public interface JetStreamSubscription extends Subscription {
109103
* <p>
110104
* <code>sub.nextMessage(timeout)</code> can return a:
111105
* <ul>
112-
* <li>regular message
106+
* <li>regular JetStream message
113107
* <li>null
114108
* </ul>
115109
* <p>
116-
*
117110
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
118-
* ! Primitive API for Advanced use only. Prefer Fetch or Iterate
111+
* ! Primitive API for ADVANCED use only, officially not supported. Prefer fetch, iterate or reader.
119112
*
120113
* @param batchSize the size of the batch
121114
* @param expiresInMillis how long from now this request should be expired from the server wait list, in milliseconds
@@ -128,7 +121,6 @@ public interface JetStreamSubscription extends Subscription {
128121
* This uses <code>pullExpiresIn</code> under the covers, and manages all responses
129122
* from <code>sub.nextMessage(...)</code> to only return regular JetStream messages.
130123
* This can only be used when the subscription is pull based.
131-
*
132124
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
133125
*
134126
* @param batchSize the size of the batch
@@ -144,7 +136,6 @@ public interface JetStreamSubscription extends Subscription {
144136
* This uses <code>pullExpiresIn</code> under the covers, and manages all responses
145137
* from <code>sub.nextMessage(...)</code> to only return regular JetStream messages.
146138
* This can only be used when the subscription is pull based.
147-
*
148139
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
149140
*
150141
* @param batchSize the size of the batch
@@ -161,7 +152,6 @@ public interface JetStreamSubscription extends Subscription {
161152
* receive the first message within the max wait period. It will stop if the batch is
162153
* fulfilled or if there are fewer than batch size messages. 408 Status messages
163154
* are ignored and will not count toward the fulfilled batch size.
164-
*
165155
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
166156
*
167157
* @param batchSize the size of the batch
@@ -178,7 +168,6 @@ public interface JetStreamSubscription extends Subscription {
178168
* receive the first message within the max wait period. It will stop if the batch is
179169
* fulfilled or if there are fewer than batch size messages. 408 Status messages
180170
* are ignored and will not count toward the fulfilled batch size.
181-
*
182171
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
183172
*
184173
* @param batchSize the size of the batch
@@ -193,11 +182,8 @@ public interface JetStreamSubscription extends Subscription {
193182
* Prepares a reader. A reader looks like a push sync subscription,
194183
* meaning it is just an endless stream of messages to ask for by nextMessage,
195184
* but uses pull under the covers.
196-
*
197185
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
198186
*
199-
* THIS API IS CONSIDERED EXPERIMENTAL AND SUBJECT TO CHANGE
200-
*
201187
* @param batchSize the size of the batch
202188
* @param repullAt the point in the current batch to tell the server to start the next batch
203189
*
@@ -214,4 +200,11 @@ public interface JetStreamSubscription extends Subscription {
214200
* @throws JetStreamApiException the request had an error related to the data
215201
*/
216202
ConsumerInfo getConsumerInfo() throws IOException, JetStreamApiException;
217-
}
203+
204+
/**
205+
* Get the current status of pull requests for this subscription
206+
* ! Pull subscriptions only. Push subscription will throw IllegalStateException
207+
* @return the PullStatus object
208+
*/
209+
PullStatus getPullStatus();
210+
}

src/main/java/io/nats/client/PullRequestOptions.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
/**
2525
* The PullRequestOptions class specifies the options for pull requests
26-
*
27-
* IMPORTANT! PullRequestOptions ARE CURRENTLY EXPERIMENTAL AND SUBJECT TO CHANGE.
2826
*/
2927
public class PullRequestOptions implements JsonSerializable {
3028

src/main/java/io/nats/client/PullSubscribeOptions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* Options are set using the {@link PullSubscribeOptions.Builder} or static helper methods.
1919
*/
2020
public class PullSubscribeOptions extends SubscribeOptions {
21+
public static final PullSubscribeOptions DEFAULT_PULL_OPTS = PullSubscribeOptions.builder().build();
2122

2223
private PullSubscribeOptions(Builder builder) {
2324
super(builder, true, false, null, null, -1, -1);

src/main/java/io/nats/client/PushSubscribeOptions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* Options are set using the {@link PushSubscribeOptions.Builder} or static helper methods.
2121
*/
2222
public class PushSubscribeOptions extends SubscribeOptions {
23+
public static final PushSubscribeOptions DEFAULT_PUSH_OPTS = PushSubscribeOptions.builder().build();
2324

2425
private PushSubscribeOptions(Builder builder, boolean ordered, String deliverSubject, String deliverGroup,
2526
long pendingMessageLimit, long pendingByteLimit) {

src/main/java/io/nats/client/SubscribeOptions.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
* The SubscribeOptions is the base class for PushSubscribeOptions and PullSubscribeOptions
2626
*/
2727
public abstract class SubscribeOptions {
28-
2928
public static final long DEFAULT_ORDERED_HEARTBEAT = 5000;
3029

3130
protected final String stream;

0 commit comments

Comments
 (0)