use of org.springframework.cloud.gcp.pubsub.support.AcknowledgeablePubsubMessage in project spring-cloud-gcp by spring-cloud.
the class PubSubSubscriberTemplate method doBatchedAsyncOperation.
/**
* Perform Pub/Sub operations (ack/nack/modifyAckDeadline) in per-subscription batches.
* <p>The returned {@link ListenableFuture} will complete when either all batches completes successfully or when at
* least one fails.</p>
* <p>
* In case of multiple batch failures, which exception will be in the final {@link ListenableFuture} is
* non-deterministic.
* </p>
* @param acknowledgeablePubsubMessages messages, could be from different subscriptions.
* @param asyncOperation specific Pub/Sub operation to perform.
* @return {@link ListenableFuture} indicating overall success or failure.
*/
private ListenableFuture<Void> doBatchedAsyncOperation(Collection<? extends AcknowledgeablePubsubMessage> acknowledgeablePubsubMessages, BiFunction<String, List<String>, ApiFuture<Empty>> asyncOperation) {
Map<ProjectSubscriptionName, List<String>> groupedMessages = acknowledgeablePubsubMessages.stream().collect(Collectors.groupingBy(AcknowledgeablePubsubMessage::getProjectSubscriptionName, Collectors.mapping(AcknowledgeablePubsubMessage::getAckId, Collectors.toList())));
Assert.state(groupedMessages.keySet().stream().map(ProjectSubscriptionName::getProject).distinct().count() == 1, "The project id of all messages must match.");
SettableListenableFuture<Void> settableListenableFuture = new SettableListenableFuture<>();
int numExpectedFutures = groupedMessages.size();
AtomicInteger numCompletedFutures = new AtomicInteger();
groupedMessages.forEach((ProjectSubscriptionName psName, List<String> ackIds) -> {
ApiFuture<Empty> ackApiFuture = asyncOperation.apply(psName.toString(), ackIds);
ApiFutures.addCallback(ackApiFuture, new ApiFutureCallback<Empty>() {
@Override
public void onFailure(Throwable throwable) {
processResult(throwable);
}
@Override
public void onSuccess(Empty empty) {
processResult(null);
}
private void processResult(Throwable throwable) {
if (throwable != null) {
settableListenableFuture.setException(throwable);
} else if (numCompletedFutures.incrementAndGet() == numExpectedFutures) {
settableListenableFuture.set(null);
}
}
}, this.ackExecutor);
});
return settableListenableFuture;
}
use of org.springframework.cloud.gcp.pubsub.support.AcknowledgeablePubsubMessage in project spring-cloud-gcp by spring-cloud.
the class PubSubSubscriberTemplate method pullAndAckAsync.
@Override
public ListenableFuture<List<PubsubMessage>> pullAndAckAsync(String subscription, Integer maxMessages, Boolean returnImmediately) {
PullRequest pullRequest = this.subscriberFactory.createPullRequest(subscription, maxMessages, returnImmediately);
final SettableListenableFuture<List<PubsubMessage>> settableFuture = new SettableListenableFuture<>();
this.pullAsync(pullRequest).addCallback(ackableMessages -> {
if (!ackableMessages.isEmpty()) {
ack(ackableMessages);
}
List<PubsubMessage> messages = ackableMessages.stream().map(AcknowledgeablePubsubMessage::getPubsubMessage).collect(Collectors.toList());
settableFuture.set(messages);
}, settableFuture::setException);
return settableFuture;
}
use of org.springframework.cloud.gcp.pubsub.support.AcknowledgeablePubsubMessage in project spring-cloud-gcp by spring-cloud.
the class PubSubSubscriberTemplate method pullAndAck.
@Override
public List<PubsubMessage> pullAndAck(String subscription, Integer maxMessages, Boolean returnImmediately) {
PullRequest pullRequest = this.subscriberFactory.createPullRequest(subscription, maxMessages, returnImmediately);
List<AcknowledgeablePubsubMessage> ackableMessages = pull(pullRequest);
if (!ackableMessages.isEmpty()) {
ack(ackableMessages);
}
return ackableMessages.stream().map(AcknowledgeablePubsubMessage::getPubsubMessage).collect(Collectors.toList());
}
use of org.springframework.cloud.gcp.pubsub.support.AcknowledgeablePubsubMessage in project spring-cloud-gcp by spring-cloud.
the class PubSubSubscriberTemplateTests method testPull_AndManualAck.
@Test
public void testPull_AndManualAck() throws InterruptedException, ExecutionException, TimeoutException {
List<AcknowledgeablePubsubMessage> result = this.pubSubSubscriberTemplate.pull("sub2", 1, true);
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getPubsubMessage()).isSameAs(this.pubsubMessage);
assertThat(result.get(0).getProjectSubscriptionName().getProject()).isEqualTo("testProject");
assertThat(result.get(0).getProjectSubscriptionName().getSubscription()).isEqualTo("sub2");
AcknowledgeablePubsubMessage acknowledgeablePubsubMessage = result.get(0);
assertThat(acknowledgeablePubsubMessage.getAckId()).isNotNull();
TestListenableFutureCallback testListenableFutureCallback = new TestListenableFutureCallback();
ListenableFuture<Void> listenableFuture = this.pubSubSubscriberTemplate.ack(result);
assertThat(listenableFuture).isNotNull();
listenableFuture.addCallback(testListenableFutureCallback);
listenableFuture.get(10L, TimeUnit.SECONDS);
assertThat(listenableFuture.isDone()).isTrue();
assertThat(testListenableFutureCallback.getThrowable()).isNull();
}
use of org.springframework.cloud.gcp.pubsub.support.AcknowledgeablePubsubMessage in project spring-cloud-gcp by spring-cloud.
the class PubSubSubscriberTemplateTests method testPull_AndManualMultiSubscriptionAck.
@Test
public void testPull_AndManualMultiSubscriptionAck() throws InterruptedException, ExecutionException, TimeoutException {
ExecutorService mockExecutor = Mockito.mock(ExecutorService.class);
this.pubSubSubscriberTemplate.setAckExecutor(mockExecutor);
List<AcknowledgeablePubsubMessage> result1 = this.pubSubSubscriberTemplate.pull("sub1", 1, true);
List<AcknowledgeablePubsubMessage> result2 = this.pubSubSubscriberTemplate.pull("sub2", 1, true);
Set<AcknowledgeablePubsubMessage> combinedMessages = new HashSet<>(result1);
combinedMessages.addAll(result2);
assertThat(combinedMessages.size()).isEqualTo(2);
TestListenableFutureCallback testListenableFutureCallback = new TestListenableFutureCallback();
ListenableFuture<Void> listenableFuture = this.pubSubSubscriberTemplate.ack(combinedMessages);
assertThat(listenableFuture).isNotNull();
listenableFuture.addCallback(testListenableFutureCallback);
listenableFuture.get(10L, TimeUnit.SECONDS);
assertThat(listenableFuture.isDone()).isTrue();
assertThat(testListenableFutureCallback.getThrowable()).isNull();
verify(this.ackCallable, times(2)).futureCall(any(AcknowledgeRequest.class));
verify(this.ackApiFuture, times(2)).addListener(any(), same(mockExecutor));
}
Aggregations