Skip to content

Commit 0e20d80

Browse files
fix: Fix BufferingPullSubscriber to not seek after sending flow control tokens. (#253)
Seeking after sending tokens will discard any flow control tokens sent to the server. Also, update BufferingPullSubscriber to accept arbitrary initial seek requests.
1 parent eabe900 commit 0e20d80

File tree

3 files changed

+27
-22
lines changed

3 files changed

+27
-22
lines changed

google-cloud-pubsublite/src/main/java/com/google/cloud/pubsublite/internal/BufferingPullSubscriber.java

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@
1818

1919
import com.google.api.core.ApiService.Listener;
2020
import com.google.api.core.ApiService.State;
21-
import com.google.cloud.pubsublite.Offset;
2221
import com.google.cloud.pubsublite.SequencedMessage;
2322
import com.google.cloud.pubsublite.cloudpubsub.FlowControlSettings;
2423
import com.google.cloud.pubsublite.internal.wire.Subscriber;
2524
import com.google.cloud.pubsublite.internal.wire.SubscriberFactory;
26-
import com.google.cloud.pubsublite.proto.Cursor;
2725
import com.google.cloud.pubsublite.proto.FlowControlRequest;
2826
import com.google.cloud.pubsublite.proto.SeekRequest;
27+
import com.google.cloud.pubsublite.proto.SeekRequest.NamedTarget;
2928
import com.google.common.collect.ImmutableList;
3029
import com.google.common.util.concurrent.MoreExecutors;
3130
import io.grpc.StatusException;
@@ -42,6 +41,15 @@ public class BufferingPullSubscriber implements PullSubscriber<SequencedMessage>
4241

4342
public BufferingPullSubscriber(SubscriberFactory factory, FlowControlSettings settings)
4443
throws StatusException {
44+
this(
45+
factory,
46+
settings,
47+
SeekRequest.newBuilder().setNamedTarget(NamedTarget.COMMITTED_CURSOR).build());
48+
}
49+
50+
public BufferingPullSubscriber(
51+
SubscriberFactory factory, FlowControlSettings settings, SeekRequest initialSeek)
52+
throws StatusException {
4553
underlying = factory.New(messages::addAll);
4654
underlying.addListener(
4755
new Listener() {
@@ -52,29 +60,18 @@ public void failed(State state, Throwable throwable) {
5260
},
5361
MoreExecutors.directExecutor());
5462
underlying.startAsync().awaitRunning();
55-
underlying.allowFlow(
56-
FlowControlRequest.newBuilder()
57-
.setAllowedMessages(settings.messagesOutstanding())
58-
.setAllowedBytes(settings.bytesOutstanding())
59-
.build());
60-
}
61-
62-
public BufferingPullSubscriber(
63-
SubscriberFactory factory, FlowControlSettings settings, Offset initialLocation)
64-
throws StatusException {
65-
this(factory, settings);
6663
try {
67-
underlying
68-
.seek(
69-
SeekRequest.newBuilder()
70-
.setCursor(Cursor.newBuilder().setOffset(initialLocation.value()))
71-
.build())
72-
.get();
64+
underlying.seek(initialSeek).get();
7365
} catch (InterruptedException e) {
7466
throw ExtractStatus.toCanonical(e);
7567
} catch (ExecutionException e) {
7668
throw ExtractStatus.toCanonical(e.getCause());
7769
}
70+
underlying.allowFlow(
71+
FlowControlRequest.newBuilder()
72+
.setAllowedMessages(settings.messagesOutstanding())
73+
.setAllowedBytes(settings.bytesOutstanding())
74+
.build());
7875
}
7976

8077
@Override

google-cloud-pubsublite/src/test/java/com/google/cloud/pubsublite/internal/BufferingPullSubscriberTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ public class BufferingPullSubscriberTest {
5656
private final SubscriberFactory underlyingFactory = mock(SubscriberFactory.class);
5757
private final Subscriber underlying = mock(Subscriber.class);
5858
private final Offset initialOffset = Offset.of(5);
59+
private final SeekRequest initialSeek =
60+
SeekRequest.newBuilder()
61+
.setCursor(Cursor.newBuilder().setOffset(initialOffset.value()))
62+
.build();
5963
private final FlowControlSettings flowControlSettings =
6064
((Supplier<FlowControlSettings>)
6165
() -> {
@@ -102,15 +106,15 @@ public void setUp() throws Exception {
102106
.when(underlying)
103107
.addListener(any(), any());
104108

105-
subscriber = new BufferingPullSubscriber(underlyingFactory, flowControlSettings, initialOffset);
109+
subscriber = new BufferingPullSubscriber(underlyingFactory, flowControlSettings, initialSeek);
106110

107111
InOrder inOrder = inOrder(underlyingFactory, underlying);
108112
inOrder.verify(underlyingFactory).New(any());
109113
inOrder.verify(underlying).addListener(any(), any());
110114
inOrder.verify(underlying).startAsync();
111115
inOrder.verify(underlying).awaitRunning();
112-
inOrder.verify(underlying).allowFlow(flow);
113116
inOrder.verify(underlying).seek(seek);
117+
inOrder.verify(underlying).allowFlow(flow);
114118

115119
assertThat(messageConsumer).isNotNull();
116120
assertThat(errorListener).isNotNull();

pubsublite-beam-io/src/main/java/com/google/cloud/pubsublite/beam/PubsubLiteUnboundedSource.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import com.google.cloud.pubsublite.internal.BufferingPullSubscriber;
2525
import com.google.cloud.pubsublite.internal.wire.Committer;
2626
import com.google.cloud.pubsublite.internal.wire.SubscriberFactory;
27+
import com.google.cloud.pubsublite.proto.Cursor;
28+
import com.google.cloud.pubsublite.proto.SeekRequest;
2729
import com.google.common.base.Ticker;
2830
import com.google.common.collect.ImmutableList;
2931
import com.google.common.collect.ImmutableMap;
@@ -87,7 +89,9 @@ public UnboundedReader<SequencedMessage> createReader(
8789
new BufferingPullSubscriber(
8890
subscriberFactories.get(partition),
8991
subscriberOptions.flowControlSettings(),
90-
checkpointed);
92+
SeekRequest.newBuilder()
93+
.setCursor(Cursor.newBuilder().setOffset(checkpointed.value()))
94+
.build());
9195
} else {
9296
state.subscriber =
9397
new BufferingPullSubscriber(

0 commit comments

Comments
 (0)