We are using RxAndroid + retrofit for our api calls.
I sort of understand why any exceptions within the sequence will pass the Throwable through onError().
But how do you end the sequence, how do you then process a response and return to throwing fatal exceptions again? I would have expected processing in onCompleted() would allow this, but I'm still seeing onError() being called.
Simplified snippet below. Gives the result -
throwable: Attempt to invoke virtual method 'boolean java.util.ArrayList.add(java.lang.Object)' on a null object reference
Observable<ResponseModel> observable = getApiCallObservable();
AppObservable.bindFragment(this, observable)
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ResponseModel>() {
#Override
public void onCompleted() {
uninitializedList.add("item");
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "throwable: " + e.getMessage());
}
#Override
public void onNext(ResponseModel response) {
}
});
thanks for any help
I'm not sure i understood what is being asked here. Basically, if your Observable getApiCallObservable() throws an error, onError will be called and you should handle the error accordingly in onError. If that happens, as it is, nothing will happen anymore. If an error happens, onError is called and stream end. If there is no error, onNext is called, and that's where you should do anything with your response. After onNext, finally, onCompleted is called.
The error that is showing is simply saying that your arraylist uninitializedList is null, so the method call add() is invalid.
Edit. I think i got your point now. You want handle the error without onError being called by the observable. Move your oncomplete code to onNext, and it won't fall under onError, it will throw the fatal exception. is that it?
Related
My project uses the Java Netty framework to transfer messages. The application is both a client and a server. When we send a message to the remote server, we want to do some processing of this message. I use ChannelOutboundHandler.write() in my project to achieve this purpose:
public class MyOutBoundHandler extends ChannelOutboundHandlerAdapter{
#Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
process((ByteBuf) msg); // do some processing of this message
ctx.write(msg, promise);
}
}
I found a problem that when the process((ByteBuf) msg) method throws an exception, it will cause blocking, and the next method ctx.write(msg, promise) will not be executed. So how to make them asynchronous cause I hope the process((ByteBuf) msg) will not affect the writing of messages to the remote server.
If 'ctx.write(msg, promise)' does not rely on the result of the 'process((ByteBuf) msg)', you can just wrap the 'process((ByteBuf) msg)' in a runnable task and submit the task to the ThreadPool.
found a problem that when the process((ByteBuf) msg) method throws an exception, it will cause blocking, and the next method ctx.write(msg, promise) will not be executed
Unless you executing blocking code, netty will not block.
Behavior you are explaining is not blocking, it is just how control flow in java works. If an exception is thrown, none of the subsequent code will be executed unless you explicitly catch and resume.
Ideally, in your case, you want to add a try-catch block around the call to process() and if it fails, fail the promise using promise.tryFailure()
you can just add a listener for the ChannelPromise before process method was called。
refer to the following code here :
promise.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if (cause != null) {
//process happed exception will be here and you can call ctx.write(msg)
//to keep spreading forward the write event in the pipeline
ctx.write(msg);
} else {
// when msg has been write to socket successfully, netty will notify here!!
}
}
});
process(msg);
I have an HTTP request that triggers a long-running task (multiple HTTP requests to another service) that is supposed to be completed in the background while the original requests complete.
So what I do is
public void triggerWork(#RequestBody SomeObject somObject) {
return new ResponseEntity<>(startWorkAndReturn(somObject), HttpStatus.OK);
}
public void startWorkAndReturn(SomeObject someObject) {
Observable.create(observableEmitter -> {
// do the work with someObject here and at some time call
observableEmitter.onNext("result");
}).subscribe(new Observer<Object>() {
#Override
public void onSubscribe(Disposable disposable) {
}
#Override
public void onNext(Object o) {
// called at some unknown time
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onComplete() {
// currently not used as all the work is done in onNext but maybe that's a mistake
}
});
return;
}
But this seems to block the request until all the work has been done. Which already seems odd to me, since I never call onComplete, which in itself might be a mistake. But still, I am wondering how to create a request that immediately returns after triggering a background worker.
Is Flowables the solution here? I am going to refactor to those anyways to handle backpressure. Or do I need to create a background worker Thread? What is the best practice here?
Thanks
I would use Observable.fromCallable{} since you need emit only single event. That will handle onCompleate call. From information you share I don`t know how can you properly handle disposable. You should add subscribeOn() and observeOn() operators that will define on which thread 'work' should be processed and result should be observed.
Docs ref:
http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html#fromCallable-java.util.concurrent.Callable-
http://reactivex.io/documentation/operators/subscribeon.html
http://reactivex.io/documentation/operators/observeon.html
I am using CompletableFuture and have a question on exception handling.
I have a code like this, if any of validate() or process() method throws an exception then it is handled by the ExceptionHandler. However when I am using the CompletableFuture like this then the exception thrown is wrapped in CompletionException. May I know how can I make sure that my ExceptionHandler is called there instead of getting CompletionException?
CompletableFuture<Response> response = CompletableFuture
.supplyAsync(() -> {
validationService.validate(request);
return myService.process(request, headers);
});
Before calling get() on CompletableFuture call this method isCompletedExceptionally, will return true if it completes with exception
public boolean isCompletedExceptionally()
Returns true if this CompletableFuture completed exceptionally, in any way. Possible causes include cancellation, explicit invocation of completeExceptionally, and abrupt termination of a CompletionStage action.
You can also add exceptional block for the completableFuture, so while executing task if any exception occurs it will execute the exceptionally with exception an input argument
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> "Success")
.exceptionally(ex->"failed");
In the above example if any exception occurs executing supplyAsync failed will return or else Success is returned
Got it, by calling the following code, it will solve my problem
try {
response.join();
}
catch(CompletionException ex) {
try {
throw ex.getCause();
}
catch(Throwable impossible) {
throw impossible;
}
}
I want to register a callback for the future object returned from spring kafkatemplate.send().
ListenableFuture<SendResult<K, V>> org.springframework.kafka.core.KafkaTemplate.send(String topic, K key, V data)
I invoke below method on the future result of the above method.
void org.springframework.util.concurrent.ListenableFuture.addCallback(ListenableFutureCallback<? super T> callback)
like this:
kafkaTemplate.send(topicname, keyString, data).addCallback(
new ListenableFutureCallback<SendResult<String, Data>>() {
#Override
public void onFailure(Throwable ex) {
logger.error("Failure while sending message in kafka.", ex);
}
#Override
public void onSuccess(SendResult<String, Data> result) {
logger.info("Successfully sent message to kafka");
}
});
Suppose if send() completes the actual sending very fast and result is already set in future before me registering the callback. My callback registration will happen after the future.set() operation. So, there is a chance that my callback don't get executed. Isn't this a possibility?
I know such a possibility is very less. Still, can this happen? If so, what is the solution.
No, the future deals with that by immediately calling the callback after adding it, if it has already been satisfied - look at the source code for SettableListenableCallback.addCallback().
Trying to get up to speed with RxJava. I have a network call that returns no data. The only response is the code (happy path: 200, 4xx otherwise). I want to listen for this response, but all I can find is how to do it with some sort of response object.
#GET
Observable<Response<ResponseBody>> makeHttpCall(#Url String url);
So my RxJava code looks like this:
myRetrofit.makeHttpCall(url)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response<ResponseBody>>() {
#Override
public void onCompleted() {
Timber.d("on completed");
}
#Override
public void onError(Throwable e) {
if (!(e instanceof EOFException)) {
Timber.e(e, "error occurred");
}
}
#Override
public void onNext(Response<ResponseBody> responseBodyResponse) {
Timber.d("on next");
}
});
This works, but it seems like the wrong solution. I don't like how my observer drops into the onError method. My response is a 200, so I'd like to see it in the onNext or onCompleted methods.
I looked into using Completable, but that didn't work at all. I still think that might be the right way to go, however.
What is the best approach here? I'm wondering if the issue simply traces to my use of <Response<ResponseBody>> and whether there is a different type that is more appropriate in this case.
If you only care about the Http code response then something like this should surfice :
Api:
#GET
Single<Response<ResponseBody>> makeHttpCall(#Url String url);
Call:
myRetrofit.makeHttpCall(url)
.subscribeOn(Schedulers.io())
.map(Response::code)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
i -> Timber.d("code " + i),
e -> {
if (!(e instanceof EOFException)) {
Timber.e(e, "error occurred");
}
});
Also note in your original code you pass the Response<ResponseBody> to the Observer on the main thread - interacting with the ResponseBody on this thread will cause a NetworkOnMainThreadException as dealing with the body is considered a IO operation - I know not your desired intention here, but worth noting when you make api calls that require interaction with the body.
Documentation:
http://reactivex.io/RxJava/javadoc/rx/Observable.html#subscribe(rx.functions.Action1,%20rx.functions.Action1,%20rx.functions.Action0)
Subscription subscribe(Action1 onNext,
Action1 onError, Action0 onCompleted)
Subscribes to an Observable and provides callbacks to handle the items it emits and any error or completion notification it issues.
myRetrofit.makeHttpCall(url)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(n->Timber.d("on next"), e->{
if (!(e instanceof EOFException)) {
Timber.e(e, "error occurred");
}
}, ()->Timber.d("on completed"));