Skip to content

Commit 5fa68c7

Browse files
fix: Modify UnboundedRreader to correctly initialize committers. (#74)
* fix: Modify UnboundedRreader to correctly initialize committers. * fix: move FakeApiService for shared usage with beam library and fix test.
1 parent 502484a commit 5fa68c7

File tree

4 files changed

+50
-7
lines changed

4 files changed

+50
-7
lines changed

google-cloud-pubsublite/src/test/java/com/google/cloud/pubsublite/FakeApiService.java renamed to google-cloud-pubsublite/src/main/java/com/google/cloud/pubsublite/internal/FakeApiService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.google.cloud.pubsublite;
17+
package com.google.cloud.pubsublite.internal;
1818

1919
import com.google.api.core.AbstractApiService;
2020

google-cloud-pubsublite/src/test/java/com/google/cloud/pubsublite/cloudpubsub/internal/SinglePartitionSubscriberTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@
2727
import com.google.api.core.ApiService.Listener;
2828
import com.google.cloud.pubsub.v1.AckReplyConsumer;
2929
import com.google.cloud.pubsub.v1.MessageReceiver;
30-
import com.google.cloud.pubsublite.FakeApiService;
3130
import com.google.cloud.pubsublite.Message;
3231
import com.google.cloud.pubsublite.MessageTransformer;
3332
import com.google.cloud.pubsublite.Offset;
3433
import com.google.cloud.pubsublite.SequencedMessage;
3534
import com.google.cloud.pubsublite.cloudpubsub.FlowControlSettings;
3635
import com.google.cloud.pubsublite.cloudpubsub.MessageTransforms;
3736
import com.google.cloud.pubsublite.cloudpubsub.NackHandler;
37+
import com.google.cloud.pubsublite.internal.FakeApiService;
3838
import com.google.cloud.pubsublite.internal.StatusExceptionMatcher;
3939
import com.google.cloud.pubsublite.internal.wire.Subscriber;
4040
import com.google.cloud.pubsublite.internal.wire.SubscriberFactory;

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

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.cloud.pubsublite.SequencedMessage;
2424
import com.google.cloud.pubsublite.internal.CloseableMonitor;
2525
import com.google.cloud.pubsublite.internal.ExtractStatus;
26+
import com.google.cloud.pubsublite.internal.ProxyService;
2627
import com.google.cloud.pubsublite.internal.wire.Committer;
2728
import com.google.common.collect.ImmutableMap;
2829
import com.google.errorprone.annotations.concurrent.GuardedBy;
@@ -33,11 +34,14 @@
3334
import java.io.IOException;
3435
import java.util.ArrayDeque;
3536
import java.util.ArrayList;
37+
import java.util.Collection;
3638
import java.util.List;
3739
import java.util.Map;
3840
import java.util.NoSuchElementException;
3941
import java.util.Optional;
4042
import java.util.Queue;
43+
import java.util.function.Consumer;
44+
import java.util.stream.Collectors;
4145
import org.apache.beam.sdk.io.UnboundedSource;
4246
import org.apache.beam.sdk.io.UnboundedSource.CheckpointMark;
4347
import org.apache.beam.sdk.io.UnboundedSource.UnboundedReader;
@@ -52,17 +56,51 @@ class PubsubLiteUnboundedReader extends UnboundedReader<SequencedMessage>
5256
@GuardedBy("monitor.monitor")
5357
private final ImmutableMap<Partition, SubscriberState> subscriberMap;
5458

59+
private final CommitterProxy committerProxy;
60+
5561
@GuardedBy("monitor.monitor")
5662
private final Queue<PartitionedSequencedMessage> messages = new ArrayDeque<>();
5763

5864
@GuardedBy("monitor.monitor")
5965
private Optional<StatusException> permanentError = Optional.empty();
6066

67+
private static class CommitterProxy extends ProxyService {
68+
private final Consumer<StatusException> permanentErrorSetter;
69+
70+
CommitterProxy(
71+
Collection<SubscriberState> states, Consumer<StatusException> permanentErrorSetter)
72+
throws StatusException {
73+
this.permanentErrorSetter = permanentErrorSetter;
74+
addServices(states.stream().map(state -> state.committer).collect(Collectors.toList()));
75+
}
76+
77+
@Override
78+
protected void start() {}
79+
80+
@Override
81+
protected void stop() {}
82+
83+
@Override
84+
protected void handlePermanentError(StatusException error) {
85+
permanentErrorSetter.accept(error);
86+
}
87+
}
88+
6189
public PubsubLiteUnboundedReader(
6290
UnboundedSource<SequencedMessage, ?> source,
63-
ImmutableMap<Partition, SubscriberState> subscriberMap) {
91+
ImmutableMap<Partition, SubscriberState> subscriberMap)
92+
throws StatusException {
6493
this.source = source;
6594
this.subscriberMap = subscriberMap;
95+
this.committerProxy =
96+
new CommitterProxy(
97+
subscriberMap.values(),
98+
error -> {
99+
try (CloseableMonitor.Hold h = monitor.enter()) {
100+
permanentError = Optional.of(permanentError.orElse(error));
101+
}
102+
});
103+
this.committerProxy.startAsync().awaitRunning();
66104
}
67105

68106
@Override
@@ -188,14 +226,14 @@ public Instant getCurrentTimestamp() throws NoSuchElementException {
188226
public void close() {
189227
try (CloseableMonitor.Hold h = monitor.enter()) {
190228
for (SubscriberState state : subscriberMap.values()) {
191-
state.committer.stopAsync().awaitTerminated();
192229
try {
193230
state.subscriber.close();
194231
} catch (Exception e) {
195232
throw new IllegalStateException(e);
196233
}
197234
}
198235
}
236+
committerProxy.stopAsync().awaitTerminated();
199237
}
200238

201239
@Override

pubsublite-beam-io/src/test/java/com/google/cloud/pubsublite/beam/PubsubLiteUnboundedReaderTest.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.google.cloud.pubsublite.Partition;
3131
import com.google.cloud.pubsublite.SequencedMessage;
3232
import com.google.cloud.pubsublite.beam.PubsubLiteUnboundedReader.SubscriberState;
33+
import com.google.cloud.pubsublite.internal.FakeApiService;
3334
import com.google.cloud.pubsublite.internal.wire.Committer;
3435
import com.google.common.collect.ImmutableList;
3536
import com.google.common.collect.ImmutableMap;
@@ -48,6 +49,8 @@
4849
import org.junit.Test;
4950
import org.junit.runner.RunWith;
5051
import org.junit.runners.JUnit4;
52+
import org.mockito.MockitoAnnotations;
53+
import org.mockito.Spy;
5154

5255
@RunWith(JUnit4.class)
5356
public class PubsubLiteUnboundedReaderTest {
@@ -57,8 +60,10 @@ public class PubsubLiteUnboundedReaderTest {
5760
@SuppressWarnings("unchecked")
5861
private final PullSubscriber<SequencedMessage> subscriber8 = mock(PullSubscriber.class);
5962

60-
private final Committer committer5 = mock(Committer.class);
61-
private final Committer committer8 = mock(Committer.class);
63+
abstract static class CommitterFakeService extends FakeApiService implements Committer {}
64+
65+
@Spy private CommitterFakeService committer5;
66+
@Spy private CommitterFakeService committer8;
6267

6368
@SuppressWarnings("unchecked")
6469
private final UnboundedSource<SequencedMessage, ?> source = mock(UnboundedSource.class);
@@ -78,6 +83,7 @@ private static Instant toInstant(Timestamp timestamp) {
7883
}
7984

8085
public PubsubLiteUnboundedReaderTest() throws StatusException {
86+
MockitoAnnotations.initMocks(this);
8187
SubscriberState state5 = new SubscriberState();
8288
state5.subscriber = subscriber5;
8389
state5.committer = committer5;
@@ -208,6 +214,5 @@ public void checkpointMarkFinalizeCommits() throws Exception {
208214
when(committer5.commitOffset(Offset.of(10))).thenReturn(ApiFutures.immediateFuture(null));
209215
mark.finalizeCheckpoint();
210216
verify(committer5).commitOffset(Offset.of(10));
211-
verifyNoMoreInteractions(committer5, committer8);
212217
}
213218
}

0 commit comments

Comments
 (0)