mSubscriptions.add(api.signIn(phoneNumber, otp)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> Timber.e(throwable.getMessage()))
.onErrorResumeNext(throwable -> Observable.empty())
.subscribe(user -> {
// Handle user object logic here
}
}));
I generally use this pattern in all my apps for the schedulers and to handle exceptions, but sometimes i get an illegal state exceptions like this : Exception thrown on Scheduler.Worker thread. Add onError handling. Caused by rx.exceptions.OnErrorNotImplementedException, so i was wondering if this is right.
Thanks in advance.
As #yosriz mentioned - the right way is to implement onError callback in every subscriber. In your case, you're getting OnErrorNotImplementedException most likely due to your "Handle user object logic" throws.
Simple examples:
Exception in the stream:
Observable.just("value")
.flatMap(s -> Observable.error(new IllegalStateException()))
.onErrorResumeNext(t -> Observable.empty())
.doOnCompleted(() -> System.out.println("Completed"))
.subscribe(s -> {});
Completed
Exception in onNext callback:
Observable.just("value")
.onErrorResumeNext(t -> Observable.empty())
.doOnCompleted(() -> System.out.println("Completed"))
.subscribe(s -> {
throw new IllegalStateException();
});
rx.exceptions.OnErrorNotImplementedException
...
Caused by: java.lang.IllegalStateException
Exception in onNext callback, subscriber's onError implemented:
Observable.just("value")
.onErrorResumeNext(t -> Observable.empty())
.doOnCompleted(() -> System.out.println("Completed"))
.subscribe(s -> {
throw new IllegalStateException();
}, t -> {
System.out.println("Subscriber's onError triggered");
});
Subscriber's onError triggered
Arranging Schedulers has nothing to do with this type of error you get. The problem can happen if you don't have onError() handling on your subscriber (at the subscribe() method), and you get error somewhere in the stream without any handling.
doOnError() will not solve this, as it's just a side effect operator that will perform some operation with any onError().
In fact, In your example onErrorResumeNext() will handle the error as it will swallow any error, so probably you have other scenarios, where you do not handle all errors scenarios and thus got the on error not implemented exception.
As a general pattern, it's always better to prepared to any case and implement onError() at the subscriber to avoid cases where error was not handled down the stream.
Related
I have following code
IAsyncOperation<bool> trythiswork()
{
bool contentFound{ false };
try
{
auto result = co_await someAsyncFunc();
winrt::check_bool(result)
if (result)
{
contentFound = true;
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
co_return contentFound;
}
When the result is false, it fails and throws but catch goes to fail fast and program terminates. How does log function terminate the program? Isn't it supposed to only log the exception? I assumed that I am handling this exception so program won't crash but it is crashing.
So how to throw and catch so that program does not terminate? I do want to throw. And also catch and preferably log the exception as well.
Thanks
The issue can be reproduced using the following code:
IAsyncOperation<bool> someAsyncFunc() { co_return false; }
IAsyncOperation<bool> trythiswork()
{
auto contentFound { false };
try
{
auto result = co_await someAsyncFunc();
winrt::check_bool(result);
// throw std::bad_alloc {};
contentFound = true;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
co_return contentFound;
}
int main()
{
init_apartment();
auto result = trythiswork().get();
}
As it turns out, everything works as advertised, even if not as intended. When running the code with a debugger attached you will see the following debug output:
The exception %s (0x [trythiswork]
Not very helpful, but it shows that logging itself works. This is followed up by something like
FailFast(1) tid(b230) 8007023E {Application Error}
causing the process to terminate. The WIL only recognizes exceptions of type std::exception, wil::ResultException, and Platform::Exception^. When it handles an unrecognized exception type it will terminate the process by default. This can be verified by commenting out the call to check_bool and instead throwing a standard exception (such as std::bad_alloc). This produces a program that will log exception details, but continue to execute.
The behavior can be customized by registering a callback for custom exception types, giving clients control over translating between custom exception types and HRESULT values. This is useful in cases where WIL needs to interoperate with external library code that uses its own exception types.
For C++/WinRT exception types (based on hresult_error) the WIL already provides error handling helpers that can be enabled (see Integrating with C++/WinRT). To opt into this all you need to do is to #include <wil/cppwinrt.h> before any C++/WinRT headers. When using precompiled headers that's where the #include directive should go.
With that change, the program now works as desired: It logs exception information for exceptions that originate from C++/WinRT, and continues to execute after the exception has been handled.
In my logs, I found a weird error regarding my ServiceStack service. I don't have further information than the following stacktrace and I didn't manage to reproduce the error yet. That's the stacktrace:
JsvTypeSerializer.EatMapKey (ServiceStack.Text.StringSegment value, System.Int32& i)
DeserializeDictionary`1[TSerializer].ParseStringDictionary (ServiceStack.Text.StringSegment value)
(wrapper delegate-invoke) :invoke_object_StringSegment (ServiceStack.Text.StringSegment)
JsvReader`1[T].ParseStringSegment (ServiceStack.Text.StringSegment value)
JsvReader`1[T].Parse (System.String value)
TypeSerializer.DeserializeFromString[T] (System.String value)
StringExtensions.FromJsv[T] (System.String jsv)
WebServiceException.ParseResponseDto ()
WebServiceException.get_ErrorMessage ()
WebServiceException.get_Message ()
I'm not sure where I should start, the service actually only has json enabled and not jsv, and the part where I handle the request is inside a try-catch block, so I'm not sure why the error is actually happening.
This Exception is due to not being able to parse a structured Error ResponseStatus thrown in a WebServiceException possibly due to returning an unknown Error Response. I've made it so this parsing heuristic doesn't throw an Exception when it fails in this commit.
This change is available from v5.0.3 that's now available on MyGet.
With bluebird, let's say I want to catch an error and throw a different error.
DAO.getById('AccessTokens', token).then(function(matchingToken) {
return matchingToken;
}).catch(NotFoundError, function(err) {
Logging.error("caught a not found error"); // or some kind of logger...
throw err;
}).catch(function(err) {
throw ['DB Error - Tokens', err];
});
If I run this and a NotFoundError is thrown, I observe that the NotFoundError handler runs, then the generic error handler runs. I would like only the NotFoundError handler to run/propagate for a NotFoundError.
Is there a way to catch some errors and propagate them without also hitting the catchall error handler?
I could remove the catchall, but then it's possible for unknown errors to propagate. I could check for NotFoundErrors in the catchall, but that seems like duplicated behavior.. is there another option?
No, but let's talk about why
Currently - no, it was considered in the past but the use case was not convincing enough at the moment. Petka Gorgi and I discussed it in IRC at a point and generally agreed that using .catch(function(){ (a catch all) is not the greatest idea - not knowing what might fail is problematic and typically if you fail for a reason you don't know - you want to restart the server since it is unclear how you'd recover.
Personally, I'd just remove the catch-all - especially since it throws something that is not an error (so no stack trace, which is problematic and deteriorating in terms of debugging anyway). You can log errors globally and shut down gracefully.
I'm an adult and you're not the boss of me
Fine, you're right. The library is opinionated towards what I think are good error handling practices. Your opinion may vary and you can write a catch-all in the way you'd like. Sadly, I've been coding Haskell all day, so this might seem a little functional in style - you can always just catch types in the catch-all:
function typeT(type){
return function(item){ return item instanceof type; };
}
function not(fn){
return function(){ return !(fn.apply(this, arguments); };
}
DAO.getById('AccessTokens', token).then(function(matchingToken) {
return matchingToken;
}).catch(NotFoundError, function(err) {
Logging.error("caught a not found error"); // or some kind of logger...
throw err;
}).catch(not(typeT(NotFoundError)), function(err) { // predicate function catch clause
throw ['DB Error - Tokens', err];
});
I have a very specific question, and i really searched the answer all over the place...
Here is a situation: i have a Scatter-Gather component with a custom aggregation strategy.
http://clip2net.com/s/j66jK8 - Image of a subflow
Semantic of this process is rather simple. Request comes with Basic Authentication Header, the upper road calls just empty java processor, which returns original payload, the lower road authenticates user over LDAP, and returns Boolean result of this authentication process. Custom aggregation class checks result and if authentication was OK, then returns original payload, which results from the road #1. If not OK, then throws exception. Nothing wrong here, it works.
There is a bit tricky thing. If a user passed wrong authentication data then exception occurs in ldap:bind module. According to documentation exception is propagated to the Scatter-Gather so i'm trying to catch it using this:
#Override
public MuleEvent aggregate(AggregationContext context) throws MuleException {
for (MuleEvent event: context.collectEventsWithExceptions()) {
event.getMessage().getExceptionPayload().getException().printStackTrace();
throw new RuntimeException(event.getMessage().getExceptionPayload().getException());
}
MuleEvent result = DefaultMuleEvent.copy(context.getEvents().get(0));
if (!(Boolean) context.getEvents().get(1).getMessage().getPayload()) {
throw new SecurityException();
}
return result;
}
BUT!
As a result i see exception which stacktrace does not have javax.naming.AuthenticationException which was rased by ldap:bind component, and was printed to log automaticaly (see below).
So, my question is: how can i reach and rethrow this javax.naming.AuthenticationException exception out of Custom Aggregation Class?
I'd appreciate all you ideas and help. Thank you in advance.
WARN 2014-10-15 20:51:18,552 [[minkult].ScatterGatherWorkManager.02] org.mule.module.ldap.api.jndi.LDAPJNDIConnection: Bind failed.
ERROR 2014-10-15 20:51:18,559 [[minkult].ScatterGatherWorkManager.02] org.mule.retry.notifiers.ConnectNotifier: Failed to connect/reconnect: Work Descriptor. Root Exception was: javax.naming.AuthenticationException: [LDAP: error code 49 - INVALID_CREDENTIALS: Bind failed: Attempt to lookup non-existant entry: cn=sim,ou=people,dc=example,dc=com]; resolved object com.sun.jndi.ldap.LdapCtx#5de37d66. Type: class javax.naming.AuthenticationException
COUNT: 1
org.mule.api.transport.DispatchException: route number 1 failed to be executed. Failed to route event via endpoint: InterceptingChainLifecycleWrapper 'wrapper for processor chain 'null''
[
ScriptComponent{CheckAuth.component.553657235},
org.mule.module.ldap.processors.BindMessageProcessor#647af13d,
org.mule.module.ldap.processors.SearchMessageProcessor#2aac6fa7,
InvokerMessageProcessor [name=ldapUtils, object=com.at.mkrf.aggregate.LDAPUtils#5714c7da, methodName=findGroupByName, argExpressions=[#[payload], #[systemName]], argTypes=[Ljava.lang.Class;#5af349a6]
]. Message payload is of type: NullPayload
On a CompositeRoutingException, you can call:
exception.getExceptions().values()
to get an Array of Throwables thrown from within the scatter-gather. Then just re-throw the appropriate exception.
We've noticed a couple of times in our mobile applications that users have reported the application hanging or seeming to become unresponsive between views / rare crashes when switching between views. We've tracked down these cases to when our view model constructors throw uncaught exceptions.
We want to put a solution in place so that if a view model fails to construct for some reason then we can notify the user and provide some message that will be useful to us when it's logged through support.
I've been taking a look at doing this but haven't found a reliable way to achieve this.
The first thing we tried was at the IMvxViewModelLocator level. We already have a custom implementation of IMvxViewModelLocator so we've modified this. We allow all exceptions to be thrown and then we have an IErrorHandler interface which each platform implements. We then call this to attempt to show a dialog. This has proved to be unreliable and the dialog does not always display. Something along the lines of: (note - here ResolveViewModel will always return true or throw)
public override bool TryLoad(Type viewModelType, IMvxBundle parameterValues, IMvxBundle savedState, out IMvxViewModel viewModel)
{
try
{
return ResolveViewModel(viewModelType, parameterValues, savedState, out viewModel);
}
catch (Exception exception)
{
_errorHandler.HandleViewModelConstructionException(viewModelType, exception);
viewModel = null;
return false;
}
}
What we would ideally like to do is intercept any failure to construct a view model and then re-request an ErrorViewModel. We've tried to do this 2 ways:
1)
We've tried defining a custom IMvxViewDispatcher for each platform and we're trying to intercept failures as below but if an exception in the constructor is thrown we never get back this far:
public class TouchDispatcher : MvxTouchUIThreadDispatcher, IMvxViewDispatcher
{
private readonly IMvxTouchViewPresenter _presenter;
public TouchDispatcher(IMvxTouchViewPresenter presenter)
{
_presenter = presenter;
}
public bool ShowViewModel(MvxViewModelRequest request)
{
Action action = () =>
{
_presenter.Show(request);
};
try
{
bool success = RequestMainThreadAction(action);
return !success ? HandleError() : success;
}
catch (Exception)
{
return HandleError();
}
}
// Other bits
}
2)
We thought we might have more success at the presenter level. We modified our ViewPresenter for each platform and we have overridden void Show(MvxViewModelRequest request). This has not proved to be successful either as exceptions don't propagate back this far.
This leaves me thinking that maybe we are better attempting this at the IMvxViewModelLocator level again.
Has anyone found a way to reliably intercept failures to construct view models and then ideally re-request a different view model / present some dialog to the user?
It seems you've identified that the core of the problem is when: "view model constructors throw uncaught exceptions."
This is going to be slightly problematic as the ViewModel's are generally constructed during View lifecycle overrides like ViewDidLoad, OnCreate or NavigatedTo - which is generally after the Presenter has finished requesting presentation.
As you've already found an easy place to identify when ViewModel construction has failed is in a custom IMvxViewModelLocator - others likeIMvxViewModelLoader are also possible. This is probably the easiest place to catch the error and to trigger the error handling - you can then get hold of the IMvxViewDispatcher (or presenter) there in order to change the display. However, you will still need to make sure your Views can handle null created ViewModels - as the ViewDidLoad, etc calls will still need to complete.