Checking for errors/exception while using await in ListenableFuture Kotlin - kotlin

I am new to Kotlin, and while I am aware of the concept about ListenableFuture, and how we can add callbacks to it for checking for success or failure.
However, I am trying to use await (https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/await.html) feature.
There is a library function I am calling and this is how it looks like:
#NonNull
ListenableFuture<Void> removeAsync(#NonNull String queryExpression,
#NonNull SearchSpec searchSpec);
/**
* #deprecated use {#link #removeAsync}
*
* #param queryExpression Query String to search.
* #param searchSpec Spec containing schemaTypes, namespaces and query expression
* indicates how document will be removed. All specific about how to
* scoring, ordering, snippeting and resulting will be ignored.
* #return The pending result of performing this operation.
*/
#NonNull
#Deprecated
default ListenableFuture<Void> remove(#NonNull String queryExpression,
#NonNull SearchSpec searchSpec) {
return removeAsync(queryExpression, searchSpec);
}
Now, I am calling this function like this:
suspend fun removeDocs() {
val removeQuery = SearchSpec.Builder().addFilterSchemas("MyDocument").build()
appSearchSession.removeAsync("", removeQuery).await()
}
Now, I don't understand how do I check for the success of this operation? What sort of error handling can I do in removeDocs function?

Coroutines allow to execute asynchronous operations using classic sequential code. Then we don't have to use callbacks or check for some flags in order to handle exceptions. Exceptions are handled directly - by throwing them.
If await() didn't throw an exception, that means the operation succeeded:
appSearchSession.removeAsync("", removeQuery).await()
// if we get here, remove succeeded
If you have to react somehow to the failed operation, use try...catch:
try {
appSearchSession.removeAsync("", removeQuery).await()
// remove succeeded
catch (e: Throwable) {
// remove failed
}

Related

Can I receive multiple messages from Spring AMQP RabbitTemplate at one request?

I want to receive multiple messages on one request from Spring AMQP RabbitTemplate (https://docs.spring.io/spring-amqp/api/org/springframework/amqp/rabbit/core/RabbitTemplate.html).
But I can't find the method working this way. Can I do that in Spring AMQP?
I don't want to use RabbitListener because it consumes all the time..
No, there is no such an API on the RabbitTemplate, as well as there is no way to send several message per single publish.
You may consider to use this one instead of receive():
/**
* Execute the callback with a channel and reliably close the channel afterwards.
* #param action the call back.
* #param <T> the return type.
* #return the result from the
* {#link ChannelCallback#doInRabbit(com.rabbitmq.client.Channel)}.
* #throws AmqpException if one occurs.
*/
#Nullable
<T> T execute(ChannelCallback<T> action) throws AmqpException;
So, you can call the Channel.basicGet() in a loop on the same opened channel.
However there is also this more higher API:
/**
* Invoke the callback and run all operations on the template argument in a dedicated
* thread-bound channel and reliably close the channel afterwards.
* #param action the call back.
* #param <T> the return type.
* #return the result from the
* {#link OperationsCallback#doInRabbit(RabbitOperations operations)}.
* #throws AmqpException if one occurs.
* #since 2.0
*/
#Nullable
default <T> T invoke(OperationsCallback<T> action) throws AmqpException {
So, you can call RabbitOperations.receive() in a loop.

Can ANTLR4 parsers (in Java) be instrumented to be interruptible?

I'd like to run my ANTLR parser with an ExecutorService so I can call Future.cancel() on it after a timeout. AIUI, I need the parser to check Thread.isInterrupted(); is there a mechanism in the parser interface for this kind of instrumentation?
In the cases where this is relevant, the parser seems to be deep in PredictionContext recursion.
There is a ParseCancellationException (https://javadoc.io/doc/org.antlr/antlr4-runtime/latest/index.html).
Per the docs: “This exception is thrown to cancel a parsing operation. This exception does not extend RecognitionException, allowing it to bypass the standard error recovery mechanisms. BailErrorStrategy throws this exception in response to a parse error.”
You can attach a Listener that overrides enterEveryRule() to your parser. You could have a method on that listener to set a flag to throw the ParseCancellationException the next time the parser enters a rule (which happens very frequently).
Here's a short example of what the listener might look like:
public class CancelListener extends YourBaseListener {
public boolean cancel = false;
#Override
public void enterEveryRule(ParserRuleContext ctx) {
if (cancel) {
throw new ParseCancellationException("gotta go");
}
super.enterEveryRule(ctx);
}
}
then you can add that listener to your parser:
parser.addParseListener(cancelListener);
And then:
cancelListener.cancel = true

Spring Cloud Stream deserialization error handling for Batch processing

I have a question about handling deserialization exceptions in Spring Cloud Stream while processing batches (i.e. batch-mode: true).
Per the documentation here, https://docs.spring.io/spring-kafka/docs/2.5.12.RELEASE/reference/html/#error-handling-deserializer, (looking at the implementation of FailedFooProvider), it looks like this function should return a subclass of the original message.
Is the intent here that a list of both Foo's and BadFoo's will end up at the original #StreamListener method, and then it will be up to the code (i.e. me) to sort them out and handle separately? I suspect this is the case, as I've read that the automated DLQ sending isn't desirable for batch error handling, as it would resubmit the whole batch.
And if this is the case, what if there is more than one message type received by the app via different #StreamListener's, say Foo's and Bar's. What type should the value function return in that case? Below is the pseudo code to illustrate the second question?
#StreamListener
public void readFoos(List<Foo> foos) {
List<> badFoos = foos.stream()
.filter(f -> f instanceof BadFoo)
.map(f -> (BadFoo) f)
.collect(Collectors.toList());
// logic
}
#StreamListener
public void readBars(List<Bar> bars) {
// logic
}
// Updated to return Object and let apply() determine subclass
public class FailedFooProvider implements Function<FailedDeserializationInfo, Object> {
#Override
public Object apply(FailedDeserializationInfo info) {
if (info.getTopics().equals("foo-topic") {
return new BadFoo(info);
}
else if (info.getTopics().equals("bar-topic") {
return new BadBar(info);
}
}
}
Yes, the list will contain the function result for failed deserializations; the application needs to handle them.
The function needs to return the same type that would have been returned by a successful deserialization.
You can't use conditions with batch listeners. If the list has a mixture of Foos and Bars, they all go to the same listener.

Can someone explain to me what's the proper usage of gRPC StreamObserver.onError?

I am trying to handle gRPC errors properly (Java, Spring-boot app).
Basically, I need too transfer error details from gRPC server to client, but I find it hard to understand the proper usage of StreamObserver.onError();
The method doc says:
"Receives a terminating error from the stream. May only be called once
and if called it must be the last method called. In particular if an
exception is thrown by an implementation of onError no further calls
to any method are allowed."
What does this "no further calls are allowed" mean? In the app that I maintain, they call other gRPC methods and they get java.lang.IllegalStateException: call already closed which is just fine, as per documentation.
I am wondering - should I (the developer) terminate the current java method (which usus gRPC calls) after an error is received? Like for example throwing an exception to stop execution. Or it is expected tht gRPC is going to terminate the execution.. (something like throwing an exception from gRPC)
Basically how do I properly use onError() and what should I expect and handle if I call it?
I need an explanation of its usage and effects.
There are two StreamObserver instances involved. One is for the inbound direction, which is the StreamObserver instance you implement and pass to the gRPC library. This is the StreamObserver containing your logic for how to handle responses. The other is for the outbound direction, which is the StreamObserver instance that gRPC library returns to you when calling the RPC method. This is the StreamObserver that you use to send requests. Most of the time, these two StreamObservers are interacting with each other (e.g., in a fully duplexed streaming call, the response StreamObserver usually calls the request StreamObserver's onNext() method, this is how you achieve ping-pong behavior).
"no further calls are allowed" means you should not call any more onNext(), onComplete() and/or onError() on the outbound direction StreamObserver when the inbound StreamObserver's onError() method is invoked, even if your implementation for the inbound onError() throws an exception. Since the inbound StreamObserver is invoked asynchronously, it has nothing to do with your method that encloses the StreamObserver's implementation.
For example:
public class HelloWorld {
private final HelloWorldStub stub;
private StreamObserver<HelloRequest> requestObserver;
...
private void sendRequest(String message) {
requestObserver.onNext(HelloRequest.newBuilder.setMessage(message).build());
}
public void start() {
stub.helloWorld(new StreamObserver<HelloResponse> {
#Override
public void onNext(HelloResponse response) {
sendRequest("hello from client");
// Optionally you can call onCompleted() or onError() on
// the requestObserver to terminate the call.
}
#Override
public void onCompleted() {
// You should not call any method on requestObserver.
}
#Override
public void onError(Throwable error) {
// You should not call any method on requestObserver.
}
});
}
}
It has nothing to do with the start() method.
The doc is also mentioning that you should not do things like
try {
requestObserver.onCompleted();
} catch(RuntimeException e) {
requestObserver.onError();
}
It's mostly for user's own StreamObserver implementations. StreamObserver's returned by gRPC never throws.
I've extracted a template for GRPC streaming which sort of abstracts away a lot of the GRPC boilerplate that also addresses the the logic for onError. In the DechunkingStreamObserver
I use the following general pattern for GRPC streaming which is something along the lines of
META DATA DATA DATA META DATA DATA DATA
An example of where I would use it would be to take one form and transform it to another form.
message SavedFormMeta {
string id = 1;
}
message SavedFormChunk {
oneof type {
SavedFormMeta meta = 1;
bytes data = 2;
}
}
rpc saveFormDataStream(stream SavedFormChunk) returns (stream SavedFormChunk) {}
I use a flag that would track the inError state to prevent further processing and catch exceptions on the onNext and onComplete both of which I redirect to onError which forwards the error to the server side.
The code below pulls the GRPC semantics and takes lamdas that do the processing.
/**
* Dechunks a GRPC stream from the request and calls the consumer when a complete object is created. This stops
* further processing once an error has occurred.
*
* #param <T> entity type
* #param <R> GRPC chunk message type
* #param <S> GRPC message type for response streams
*/
class DechunkingStreamObserver<T, R, S> implements StreamObserver<R> {
/**
* This function takes the current entity state and the chunk and returns a copy of the combined result. Note the combiner may modify the existing data, but may cause unexpected behaviour.
*/
private final BiFunction<T, R, T> combiner;
/**
* A function that takes in the assembled object and the GRPC response observer.
*/
private final BiConsumer<T, StreamObserver<S>> consumer;
/**
* Predicate that returns true if it is a meta chunk indicating a start of a new object.
*/
private final Predicate<R> metaPredicate;
/**
* this function gets the meta chunk and supplies a new object.
*/
private final Function<R, T> objectSupplier;
/**
* GRPC response observer.
*/
private final StreamObserver<S> responseObserver;
/**
* Currently being processed entity.
*/
private T current = null;
/**
* In error state. Starts {#code false}, but once it is set to {#code true} it stops processing {#link #onNext(Object)}.
*/
private boolean inError = false;
/**
* #param metaPredicate predicate that returns true if it is a meta chunk indicating a start of a new object.
* #param objectSupplier this function gets the meta chunk and supplies a new object
* #param combiner this function takes the current entity state and the chunk and returns a copy of the combined result. Note the combiner may modify the existing data, but may cause unexpected behaviour.
* #param consumer a function that takes in the assembled object and the GRPC response observer.
* #param responseObserver GRPC response observer
*/
DechunkingStreamObserver(
final Predicate<R> metaPredicate,
final Function<R, T> objectSupplier,
final BiFunction<T, R, T> combiner,
final BiConsumer<T, StreamObserver<S>> consumer,
final StreamObserver<S> responseObserver) {
this.metaPredicate = metaPredicate;
this.objectSupplier = objectSupplier;
this.combiner = combiner;
this.consumer = consumer;
this.responseObserver = responseObserver;
}
#Override
public void onCompleted() {
if (inError) {
return;
}
try {
if (current != null) {
consumer.accept(current, responseObserver);
}
responseObserver.onCompleted();
} catch (final Exception e) {
onError(e);
}
}
#Override
public void onError(final Throwable throwable) {
responseObserver.onError(throwable);
inError = true;
}
#Override
public void onNext(final R chunk) {
if (inError) {
return;
}
try {
if (metaPredicate.test(chunk)) {
if (current != null) {
consumer.accept(current, responseObserver);
}
current = objectSupplier.apply(chunk);
} else {
current = combiner.apply(current, chunk);
}
} catch (final Exception e) {
onError(e);
}
}
}
I have 4 lamdas
Predicate<R> metaPredicate which takes in a chunk and returns whether the chunk is meta or not.
Function<R, T> objectSupplier which takes in a meta chunk and creates a new object that is used by your module.
BiFunction<T, R, T> combiner, which takes in a data chunk and the current object and returns a new object that contains the combination.
BiConsumer<T, StreamObserver<S>> consumer which will consume a completed object. It also passes in a stream observer in the case of sending new objects in response.
the only thing you want to do is mark as return after calling the responseObserver.onError(); like below. because there is nothing to do after sending the error.
if(condition){
responseObserver.onError(StatusProto.toStatusException(status));
//this is the required part
return;
}else{
responseObserver.onComplete(DATA);
}

Kotlin assignments are not expressions. Any other way to force assertions to be enabled?

I'm currently learning Kotlin, and one way I'm doing it is by automatically converting Java code to Kotlin and studying the results. One piece of Java code I tried to convert is the following static block in a class that tries to ensure that assertions are enabled:
static {
boolean assertsEnabled = false;
assert assertsEnabled = true;
if (!assertsEnabled)
throw new AssertionError("Please enable assertions!");
}
This relies on the assertsEnabled = true expression as an argument to assert. In Java, assignments are expressions. In Kotlin, they're not, and so this can't be converted. Is there any other way to do it?
Unfortunately, Kotlin doesn't have the assert keyword with its special semantics. Instead it has this function:
inline fun assert(value: Boolean, lazyMessage: () -> Any)
You can see that the expression passed as the first argument is evaluated unconditionally. This means you can't achieve the same lightweight check as in Java; you have to trigger an actual assertion failure to make sure.
So you need a check as suggested by #Zoe:
try {
assert(false)
throw IllegalStateException("Please enable assertions!")
} catch (e: AssertionError) {
// Things are looking good; carry on
}
If you insist on throwing an AssertionError instead of IllegalStateException, you can use a boolean variable for that.
var assertionsAreDisabled = false
try {
assert(false)
assertionsAreDisabled = true
} catch (e: AssertionError) {
// Things are looking good; carry on
}
if (assertionsAreDisabled) {
throw AssertionError("Please enable assertions!")
}