Handling exception in background? - android-annotations

I found that I am forced to throw exception in a background thread:
#Background
void bootstrap() throws IOException {
mProgressBar.setVisibility(View.VISIBLE);
restClient.setBearerAuth(Auth.token);
UserID userIdJsonn = restClient.getUserId();
Auth.user_id= userIdJsonn.getUser_id();
PhoenixPlug.getInstance().ini();
mProgressBar.setVisibility(View.GONE);
}
Of course, I've got this error:
Error:(619, 5) error: org.androidannotations.annotations.Background annotated methods should not declare throwing any exception
So, what's the recommended way to handle such a case?

If you are using a background annotation, you have to catch the exception locally.

Related

Catching vs. not catching specific error types in dart - any difference in behavior?

My understanding of catching errors was that if a certain error is 'caught', the code in a method following the catch block would not execute unless you have a finally statement afterwards.
However, if I catch a certain error type, but don't have a return or a throw/rethrow statement at the end, it does seem to keep going with the further code in the method.
I am catching a certain exception type, with the statement on CustomException catch (error) but I'm not planning to rethrow the error, and I don't need to do anything with the actual error. I don't have a return or a rethrow statement, as I assumed the catch block. I have two questions to make sure I'm understanding this behavior properly:
First question - if I don't plan to use the specific error inside my catch block, does adding catch (error) after on CustomException actually make a difference? It seems like it's ok to do it with or without it.
Second question - does my catch block need to have a return/throw/rethrow statement at the end in all cases to prevent the method from performing any further code?
Code example 1: With the catch (error) statement:
try {
...
} on CustomException catch (error) {
...
} catch (error) {
rethrow;
}
print('Is this method still running?');
Code example 2: without the catch (error) statement:
try {
...
} on CustomException {
...
} catch (error) {
rethrow;
}
print('Is this method still running?');
Your two examples aren't the same; one catches CustomException and the other catches PlatformException. Presuming that you meant them to be the same, then the difference between on CustomException and on CustomException catch (error) is that the second way allows you to do something with the thrown object (or if you use on CustomException catch (error, stacktrace), to do something with the stacktrace too).
The Dart Language Tour covers this:
Use on when you need to specify the exception type. Use catch when your exception handler needs the exception object.
Additionally, doing:
catch (error) {
rethrow;
}
is unnecessary noise. Just omit it and let the thrown exception go uncaught.

Not caching error signals in Mono.cache()

Hello good reactor folks - I trying to write some reactive code (surprising eh?) and have hit a slight snag. I think it might be a reactor bug, but thought I'd ask here first before posting a bug.
For context: I have a cache Map<Key, Mono<Value>>. A client will request data - we check the cache and use what is essentially computeIfAbsent to place a Mono with .cache() into the cache if nothing has yet been cached for that key. The client then takes the Mono and does magic (not relevant here). Now, the catch is that the population of the cache may encounter transient errors, so we don't want to cache errors - the current request will error but the "next" client, when it subscribes, should trigger the entire pipeline to rerun.
Having read around, for example this closed issue, I settled on Mono#cache(ttlForValue, ttlForError, ttlForEmpty).
This is where things get interesting.
As I don't want to cache error (or empty, but ignore that) signals I found the following documentation promising
If the relevant TTL generator throws any Exception, that exception will be propagated to the Subscriber that encountered the cache miss, but the cache will be immediately cleared, so further Subscribers might re-populate the cache in case the error was transient. In case the source was emitting an error, that error is dropped and added as a suppressed exception. In case the source was emitting a value, that value is dropped.
emphasis mine
So I tried the following (shamelessly cribbing the example in the linked GitHub issue)
public class TestBench {
public static void main(String[] args) throws Exception {
var sampleService = new SampleService();
var producer = Mono.fromSupplier(sampleService::call).cache(
__ -> Duration.ofHours(24),
//don't cache errors
e -> {throw Exceptions.propagate(e);},
//meh
() -> {throw new RuntimeException();});
try {
producer.block();
} catch (RuntimeException e) {
System.out.println("Caught exception : " + e);
}
sampleService.serverAvailable = true;
var result = producer.block();
System.out.println(result);
}
static final class SampleService {
volatile boolean serverAvailable = false;
String call() {
System.out.println("Calling service with availability: " + serverAvailable);
if (!serverAvailable) throw new RuntimeException("Error");
return "Success";
}
}
}
Output
09:12:23.991 [main] DEBUG reactor.util.Loggers$LoggerFactory - Using Slf4j logging framework
Calling service with availability: false
09:12:24.034 [main] ERROR reactor.core.publisher.Operators - Operator called default onErrorDropped
java.lang.RuntimeException: Error
at uk.co.borismorris.testbench.TestBench$SampleService.call(TestBench.java:40)
at reactor.core.publisher.MonoSupplier.subscribe(MonoSupplier.java:56)
at reactor.core.publisher.MonoCacheTime.subscribe(MonoCacheTime.java:123)
at reactor.core.publisher.Mono.block(Mono.java:1474)
at uk.co.borismorris..boris.testbench.TestBench.main(TestBench.java:26)
Caught exception : reactor.core.Exceptions$BubblingException: java.lang.RuntimeException: Error
Exception in thread "main" java.lang.RuntimeException: Error
at uk.co.borismorris.testbench.TestBench$SampleService.call(TestBench.java:40)
at reactor.core.publisher.MonoSupplier.subscribe(MonoSupplier.java:56)
at reactor.core.publisher.MonoCacheTime.subscribe(MonoCacheTime.java:123)
at reactor.core.publisher.Mono.block(Mono.java:1474)
at uk.co.borismorris.testbench.TestBench.main(TestBench.java:26)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:93)
at reactor.core.publisher.Mono.block(Mono.java:1475)
at uk.co.borismorris.testbench.TestBench.main(TestBench.java:31)
Well, that didn't work - the error is cached and the second subscriber just sees the same error.
Looking at the code the cause is obvious
Duration ttl = null;
try {
ttl = main.ttlGenerator.apply(signal);
}
catch (Throwable generatorError) {
signalToPropagate = Signal.error(generatorError);
STATE.set(main, signalToPropagate); //HERE
if (signal.isOnError()) {
//noinspection ThrowableNotThrown
Exceptions.addSuppressed(generatorError, signal.getThrowable());
}
}
The STATE is set to the error signal, not cleared at all. But this isn't the whole story,
the reason for the code not clearing the cache is below this block
if (ttl != null) {
main.clock.schedule(main, ttl.toMillis(), TimeUnit.MILLISECONDS);
}
else {
//error during TTL generation, signal != updatedSignal, aka dropped
if (signal.isOnNext()) {
Operators.onNextDropped(signal.get(), currentContext());
}
else if (signal.isOnError()) {
Operators.onErrorDropped(signal.getThrowable(), currentContext());
}
//immediate cache clear
main.run();
}
In this case ttl == null because the generation of the ttl threw an Exception. The signal is an error so that branch is entered and Operators.onErrorDropped is called
public static void onErrorDropped(Throwable e, Context context) {
Consumer<? super Throwable> hook = context.getOrDefault(Hooks.KEY_ON_ERROR_DROPPED,null);
if (hook == null) {
hook = Hooks.onErrorDroppedHook;
}
if (hook == null) {
log.error("Operator called default onErrorDropped", e);
throw Exceptions.bubble(e);
}
hook.accept(e);
}
So here we can see that if there is no onError hook in the context and no default set then throw Exceptions.bubble(e) is called and the code in MonoCacheTime returns early, failing to call main.run(). Hence the error stays cached indefinitely as there is no TTL!
The following code fixes that problem
public class TestBench {
private static final Logger logger = LoggerFactory.getLogger(TestBench.class);
private static final Consumer<Throwable> onErrorDropped = e -> logger.error("Dropped", e);
static {
//add default hook
Hooks.onErrorDropped(onErrorDropped);
}
public static void main(String[] args) throws Exception {
var sampleService = new SampleService();
var producer = Mono.fromSupplier(sampleService::call).cache(
__ -> Duration.ofHours(24),
//don't cache errors
e -> {throw Exceptions.propagate(e);},
//meh
() -> {throw new RuntimeException();});
try {
producer.block();
} catch (RuntimeException e) {
System.out.println("Caught exception : " + e);
}
sampleService.serverAvailable = true;
var result = producer.block();
System.out.println(result);
}
static final class SampleService {
volatile boolean serverAvailable = false;
String call() {
System.out.println("Calling service with availability: " + serverAvailable);
if (!serverAvailable) throw new RuntimeException("Error");
return "Success";
}
}
}
But this adds a global Hook, which isn't ideal. The code hints at the ability to add per-pipeline hooks, but I cannot figure out how to do that. The following works, but is obviously a hack
.subscriberContext(ctx -> ctx.put("reactor.onErrorDropped.local", onErrorDropped))
Questions
Is the above a bug, should the absence of a onErrorDropped hook cause errors to be cached indefinitely?
Is there a way to set the onErrorDropped hook in the subscriberContext rather than globally?
Follow up
From the code; it seems that returning null from a TTL generator function is supported and has the same behaviour when the signal is immediately cleared. In the case where it isn't, the subscriber sees the original error rather than the error from the TTL generator and a suppressed error - which seems perhaps neater
public static void main(String[] args) throws Exception {
var sampleService = new SampleService();
var producer = Mono.fromSupplier(sampleService::call).cache(
__ -> Duration.ofHours(24),
//don't cache errors
e -> null,
//meh
() -> null);
try {
producer.block();
} catch (RuntimeException e) {
System.out.println("Caught exception : " + e);
}
sampleService.serverAvailable = true;
var result = producer.block();
System.out.println(result);
}
Is this behaviour supported? Should it be documented?
You've indeed found a bug! And I think the documentation can also be improved for this variant of cache:
The focus on how it deals with exceptions inside TTL Function is probably misleading
There should be a documented straightforward way of "ignoring" a category of signals in the source (which is you case: you want subsequent subscribers to "retry" when the source is erroring).
The behavior is bugged due to the use of onErrorDropped (which defaults to throwing the dropped exception, thus preventing the main.run() state reset).
Unfortunately, the tests use StepVerifier#verifyThenAssertThat(), which set an onErrorDropped hook, so that last bug was never identified.
Returning null in the TTL function is not working better because the same bug happens, but this time with the original source exception being dropped/bubbled.
But there is an ideal semantic for propagating an error to the first subscriber and let the second subscriber retry: to return Duration.ZERO in the ttl Function. This is undocumented, but works right now:
IllegalStateException exception = new IllegalStateException("boom");
AtomicInteger count = new AtomicInteger();
Mono<Integer> source = Mono.fromCallable(() -> {
int c = count.incrementAndGet();
if (c == 1) throw exception;
return c;
});
Mono<Integer> cache = source.cache(v -> Duration.ofSeconds(10),
e -> Duration.ZERO,
() -> Duration.ofSeconds(10));
assertThat(cache.retry().block()).isEqualTo(2);
I'll open an issue to fix the state reset bug and focus the javadoc on the above solution, while moving the bit dealing with throwing TTL Functions in a separate shorter paragraph at the end.
edit: https://github.com/reactor/reactor-core/issues/1783

"Operator called default onErrorDropped" on Mono timeout

In my Production code, I am getting errors in my logs when a Mono times out.
I have managed to recreate these errors with the following code:
#Test
public void testScheduler() {
Mono<String> callableMethod1 = callableMethod();
callableMethod1.block();
Mono<String> callableMethod2 = callableMethod();
callableMethod2.block();
}
private Mono<String> callableMethod() {
return Mono.fromCallable(() -> {
Thread.sleep(60);
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"));
}
In the Mono.fromCallable I am making a blocking call using a third-party library. When this call times out, I get errors similar to
reactor.core.publisher.Operators - Operator called default onErrorDropped
reactor.core.publisher.Operators - Scheduler worker in group main failed with an uncaught exception
These errors also seem to be intermittent, sometimes when I run the code provided I get no errors at all. However when I repeat the call in a loop of say 10, I consistently get them.
Question: Why does this error happen?
Answer:
When the duration given to the timeout() operator has passed, it throws a TimeoutException. That results in the following outcomes:
An onError signal is sent to the main reactive chain. As a result, the main execution is resumed and the process moves on (i.e., onErrorResume() is executed).
Shortly after outcome #1, the async task defined within fromCallable() is interrupted, which triggers a 2nd exception (InterruptedException). The main reactive chain can no longer handle this InterruptedException because the TimeoutException happened first and already caused the main reactive chain to resume (Note: this behavior of not generating a 2nd onError signal conforms with the Reactive Stream Specification -> Publisher #7).
Since the 2nd exception (InterruptedException) can't be handled gracefully by the main chain, Reactor logs it at error level to let us know an unexpected exception occurred.
Question: How do I get rid of them?
Short Answer: Use Hooks.onErrorDropped() to change the log level:
Logger logger = Logger.getLogger(this.getClass().getName());
#Test
public void test() {
Hooks.onErrorDropped(error -> {
logger.log(Level.WARNING, "Exception happened:", error);
});
Mono.fromCallable(() -> {
Thread.sleep(60);
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"))
.doOnSuccess(result -> logger.info("Result: " + result))
.block();
}
Long Answer: If your use-case allows, you could handle the exception happening within fromCallable() so that the only exception affecting the main chain is the TimeoutException. In that case, the onErrorDropped() wouldn't happen in the first place.
#Test
public void test() {
Mono.fromCallable(() -> {
try {
Thread.sleep(60);
} catch (InterruptedException ex) {
//release resources, rollback actions, etc
logger.log(Level.WARNING, "Something went wrong...", ex);
}
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"))
.doOnSuccess(result -> logger.info("Result: " + result))
.block();
}
Extra References:
https://tacogrammer.com/onerrordropped-explained/
https://medium.com/#kalpads/configuring-timeouts-in-spring-reactive-webclient-4bc5faf56411

Catch an objectiveC exception that was thrown as a result of a javascript script

Is there any way of catching an Objective-C exception that was thrown as a result of a JavaScript script evaluation?
For example:
I have a class Obj with a method canThrow that I have exported through JSExport. From some script I call this method and it indeed throws an exception.
Any way I can handle it?
I have already tried to wrap the script evaluation code in a try-catch, but that didn't help.
Your question is a little bit unclear, but I will try to answer it anyway.
If you need to raise an exception from Objective-C to Javascript, you should use -[JSContext exception] property. See following question for details.
Passing exception from Javascript to Objective-C is straightforward, you simply export some method, that will handle exception in Objective-C like:
myJSContext[#"PassExceptionToObjC"] = ^void(JSValue *)jsException {
// Handle exception
}
And then use following code in Javascript:
try {
// some code
}
catch (exception) {
PassExceptionToObjC(exception);
}
Alternatively you can return specific value from your Javascript to Objective-C. Like:
function doSomething() {
try {
// Do something
return 'Ok';
}
catch (error) {
return 'Error happens ' + error.message;
}
}
In case you need to avoid throwing Objective-C exception in method, called from Javascript, you simply should add #try/#catch in your Objective-C method or block:
myJSContext[#"DoSomething"] = ^void(JSValue *)someValue {
#try {
// Do something
}
#catch (NSException *exception) {
// Handle exception
}
}
Or, preferred, change logic of Objective-C code, that trigger exception.
Similar way applies if you need to avoid exception in Javascript, called from Objective-C. You simply add try/catch. In most cases you may simply ignore exceptions in JavaScript, called from Objective-C. But I suggest to implement exception handing on Objective-C side for any non-trivial Javascript, at least to simplify troubleshooting.
Hope it helps.

When to use Future.handleexception in Dart and when to try-catch

I'm trying to really get Futures in Dart and I've noticed that just about every example I come across uses handleException to deal with exceptions that complete the Future. Yet the API documentation states "In most cases it should not be necessary to call handleException, because the exception associated with this Future will propagate naturally if the future's value is being consumed. Only call handleException if you need to do some special local exception handling related to this particular Future's value."
So when would I need "special local exception handling"? Could someone explain that in a bit more detail? Is there some code that I honestly can't run easily by letting the exception propagate?
Mads Ager gave me this answer:
Basically, this is the equivalent of having a try-catch in straight-line code:
int doSomethingElse() {
try {
return thisMightFail();
} catch(e) {
return -1;
}
}
void doSomething() {
int value = doSomethingElse();
// operate on value
}
With Futures it is something like this (not tested):
Future<int> doSomethingElse() {
return thisMightFail().transformException((e) => -1);
}
void doSomething() {
doSomethingElse().then((value) {
// operate on value
});
}
So this is for local exception handling instead of global exception handling. If you never use handleException or transformException that would correspond to always dealing with exceptions at the top level in non-async code.

Resources