First time using Camel Routes, all the Apache docs and the info around sof make it look very easy.... (this is in groovy, using Apache Camel and the Camel Salesforce components as libs)
class SFRouteClass extends RouteBuilder {
#Override
void configure() {
def camelRouteId
from("direct:moveFailedMessage")
.process { Exchange exchange ->
exchange.out
}
from('direct:sfe')
.onException(Exception.class)
.to('log:sfe?level=INFO&showHeaders=true&multiline=true')
.to('direct:moveFailedMessage')
.maximumRedeliveries(0)
.end()
.routeId('sfe')
.enrich('direct:salesforceCheckLeadByIDUserHashId'.toString(), new AggregationStrategy() { ..... }
}
org.apache.camel.component.salesforce.api.SalesforceException: Error {404:Not Found} executing {GET:https://.....}
at org.apache.camel.component.salesforce.internal.client.AbstractClientBase$1.onComplete(AbstractClientBase.java:176)
at org.eclipse.jetty.client.ResponseNotifier.notifyComplete(ResponseNotifier.java:193)
at org.eclipse.jetty.client.ResponseNotifier.notifyComplete(ResponseNotifier.java:185)
at org.eclipse.jetty.client.HttpReceiver.terminateResponse(HttpReceiver.java:453)
at org.eclipse.jetty.client.HttpReceiver.responseSuccess(HttpReceiver.java:400)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.messageComplete(HttpReceiverOverHTTP.java:266)
at org.eclipse.jetty.http.HttpParser.parseContent(HttpParser.java:1487)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1245)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.parse(HttpReceiverOverHTTP.java:156)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:117)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:69)
at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:89)
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:123)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.camel.component.salesforce.api.SalesforceException: {errors:[{"errorCode":"NOT_FOUND","message":"The requested resource does not exist"}],statusCode:404}
at org.apache.camel.component.salesforce.internal.client.DefaultRestClient.createRestException(DefaultRestClient.java:121)
at org.apache.camel.component.salesforce.internal.client.AbstractClientBase$1.onComplete(AbstractClientBase.java:175)
... 16 common frames omitted
This works if there is no error. My problem is the onException never triggers. I have tried to make a global errorHandler to the config, and I have tried to make a global onExcpetion. Nothing catches the error and I cannot figure out why.
You need to either
set no error handler on the route that starts at direct:salesforceCheckLeadByIDUserHashId so the route scoped error handler you have on the other route can kick in
Or add / move that onException to that route as well.
Have you tried using the doTry / doCatch way ?
from('direct:sfe')
.routeId('sfe')
.doTry()
.enrich('direct:salesforceCheckLeadByIDUserHashId'.toString(), new AggregationStrategy() { ..... }
.doCatch(Exception.class)
.to('log:sfe?level=INFO&showHeaders=true&multiline=true')
.to('direct:moveFailedMessage')
.maximumRedeliveries(0) // NOt needed as default is 0
.end()
Related
I have a situation like this where I make some web requests in parallel. Sometimes I make these calls and all requests see the same error (e.g. no-network):
void main() {
Observable.just("a", "b", "c")
.flatMap(s -> makeNetworkRequest())
.subscribe(
s -> {
// TODO
},
error -> {
// handle error
});
}
Observable<String> makeNetworkRequest() {
return Observable.error(new NoNetworkException());
}
class NoNetworkException extends Exception {
}
Depending on the timing, if one request emits the NoNetworkException before the others can, Retrofit/RxJava will dispose/interrupt** the others. I'll see one of the following logs (not all three) for each request remaining in progress++:
<-- HTTP FAILED: java.io.IOException: Canceled
<-- HTTP FAILED: java.io.InterruptedIOException
<-- HTTP FAILED: java.io.InterruptedIOException: thread interrupted
I'll be able to handle the NoNetworkException error in the subscriber and everything downstream will get disposed of and all is OK.
However based on timing, if two or more web requests emit NoNetworkException, then the first one will trigger the events above, disposing of everything down stream. The second NoNetworkException will have nowhere to go and I'll get the dreaded UndeliverableException. This is the same as example #1 documented here.
In the above article, the author suggested using an error handler. Obviously retry/retryWhen don't make sense if I expect to hear the same errors again. I don't understand how onErrorResumeNext/onErrorReturn help here, unless I map them to something recoverable to be handled downstream:
Observable.just("a", "b", "c")
.flatMap(s ->
makeNetworkRequest()
.onErrorReturn(error -> {
// eat actual error and return something else
return "recoverable error";
}))
.subscribe(
s -> {
if (s.equals("recoverable error")) {
// handle error
} else {
// TODO
}
},
error -> {
// handle error
});
but this seems wonky.
I know another solution is to set a global error handler with RxJavaPlugins.setErrorHandler(). This doesn't seem like a great solution either. I may want to handle NoNetworkException differently in different parts of my app.
So what other options to I have? What do other people do in this case? This must be pretty common.
** I don't fully understand who is interrupting/disposing of who. Is RxJava disposing of all other requests in flatmap which in turn causes Retrofit to cancel requests? Or does Retrofit cancel requests, resulting in each
request in flatmap emitting one of the above IOExceptions? I guess it doesn't really matter to answer the question, just curious.
++ It's possible that not all a, b, and c requests are in flight depending on thread pool.
Have you tried by using flatMap() with delayErrors=true?
I have a method which creates an emitter like below, there are a problem(maybe it is normal behavior) with calling onError in retrofit callback. I got UndeliverableException when try to call onError.
I can solve this by checking subscriber.isDiposed() by I wonder how can call onError coz i need to notify my UI level.
Addition 1
--> RxJava2CallAdapterFactoryalready implemented
private static Retrofit.Builder builderSwift = new Retrofit.Builder()
.baseUrl(URL_SWIFT)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(new ToStringConverterFactory());
--> When i added below code to application class app won't crash
--> but i get java.lang.exception instead of my custom exception
RxJavaPlugins.setErrorHandler(Functions<Throwable>emptyConsumer());
#Override
public void onFileUploadError(Throwable e) {
Log.d(TAG, "onFileUploadError: " + e.getMessage());
}
public Observable<UploadResponseBean> upload(final UploadRequestBean uploadRequestBean, final File file) {
return Observable.create(new ObservableOnSubscribe<UploadResponseBean>() {
#Override
public void subscribe(#NonNull final ObservableEmitter<UploadResponseBean> subscriber) throws Exception {
// ---> There are no problem with subscriber while calling onError
// ---> Retrofit2 service request
ftsService.upload(token, uploadRequestBean, body).enqueue(new Callback<UploadResponseBean>() {
#Override
public void onResponse(Call<UploadResponseBean> call, Response<UploadResponseBean> response) {
if (response.code() == 200){
// ---> calling onNext works properly
subscriber.onNext(new UploadResponseBean(response.body().getUrl()));
}
else{
// ---> calling onError throws UndeliverableException
subscriber.onError(new NetworkConnectionException(response.message()));
}
}
#Override
public void onFailure(Call call, Throwable t) {
subscriber.onError(new NetworkConnectionException(t.getMessage()));
}
});
}
});
}
Since version 2.1.1 tryOnError is available:
The emitter API (such as FlowableEmitter, SingleEmitter, etc.) now
features a new method, tryOnError that tries to emit the Throwable if
the sequence is not cancelled/disposed. Unlike the regular onError, if
the downstream is no longer willing to accept events, the method
returns false and doesn't signal an UndeliverableException.
https://github.com/ReactiveX/RxJava/blob/2.x/CHANGES.md
The problem is like you say you need to check if Subscriber is already disposed, that's because RxJava2 is more strict regarding errors that been thrown after Subscriber already disposed.
RxJava2 deliver this kind of error to RxJavaPlugins.onError that by default print to stack trace and calls to thread uncaught exception handler. you can read full explanation here.
Now what's happens here, is that you probably unsubscribed (dispose) from this Observable before query was done and error delivered and as such - you get the UndeliverableException.
I wonder how can call onError coz i need to notify my UI level.
as this is happened after your UI been unsubscribed the UI shouldn't care. in normal flow this error should delivered properly.
Some general points regarding your implementation:
the same issue will happen at the onError in case you've been unsubscribed before.
there is no cancellation logic here (that's what causing this problem) so request continue even if Subscriber unsubscribed.
even if you'll implement this logic (using ObservableEmitter.setCancellable() / setDisposable()) you will still encounter this problem in case you will unsubscribe before request is done - this will cause cancellation and your onFailure logic will call onError() and the same issue will happen.
as you performing an async call via Retrofit the specified subscription Scheduler will not make the actual request happen on the Scheduler thread but just the subscription. you can use Observable.fromCallable and Retrofit blocking call execute to gain more control over the actual thread call is happened.
to sum it up -
guarding calls to onError() with ObservableEmitter.isDiposed() is a good practice in this case.
But I think the best practice is to use Retrofit RxJava call adapter, so you'll get wrapped Observable that doing the Retrofit call and already have all this considerations.
I found out that this issue was caused by using incorrect context when retrieving view model in Fragment:
ViewModelProviders.of(requireActivity(), myViewModelFactory).get(MyViewModel.class);
Because of this, the view model lived in context of activity instead of fragment. Changing it to following code fixed the problem.
ViewModelProviders.of(this, myViewModelFactory).get(MyViewModel.class);
In porting our code base from gridgain to ignite, I've found similar / renamed methods for most of the ignite methods. There are a few that I need to clarify though.
What is the ignite equivalent for
//Listener for asynchronous local node grid events. You can subscribe for local node grid event notifications via {#link GridEventStorageManager#addLocalEventListener
public interface GridLocalEventListener extends EventListener {}
What is the recommended way to invoke a compute future. See picture for compile failures.
Apart from that, it looks like future.listenAsync() should be future.listen()
final ProcessingTaskAdapter taskAdapter = new ProcessingTaskAdapter(task, manager, node);
ComputeTaskFuture<ProcessingJob> future = grid.cluster()
.forPredicate(this) //===> what should this be
.compute().execute(taskAdapter, job);
future.listen(new IgniteInClosure<IgniteFuture<ProcessingJob>>() {
#Override
public void apply(IgniteFuture<ProcessingJob> future) {
try {
// Need this to extract the remote exception, if one occurred
future.get();
} catch (IgniteException e) {
manager.fail(e.getCause() != null ? e.getCause() : e);
} finally {
manager.finishJob(job);
jobDistributor.distribute(taskAdapter.getSelectedNode());
}
}
There is no special class anymore, you simply use IgnitePredicate as a listener. Refer to [1] for details.
Refer to [2] for information about async support. Also note that projections were replaced with cluster groups [3] (one of your compile errors is because of that). And you're correct, listenAsync was renamed to listen.
[1] https://apacheignite.readme.io/docs/events
[2] https://apacheignite.readme.io/docs/async-support
[3] https://apacheignite.readme.io/docs/cluster-groups
I'm constantly (since years) wondering the most senseful way to implement the following (it's kind of paradoxic for me):
Imagine a function:
DoSomethingWith(value)
{
if (value == null) { // Robust: Check parameter(s) first
throw new ArgumentNullException(value);
}
// Some code ...
}
It's called like:
SomeFunction()
{
if (value == null) { // Fail early
InformUser();
return;
}
DoSomethingWith(value);
}
But, to catch the ArgumentNullException, should I do:
SomeFunction()
{
if (value == null) { // Fail early
InformUser();
return;
}
try { // If throwing an Exception, why not *not* check for it (even if you checked already)?
DoSomethingWith(value);
} catch (ArgumentNullException) {
InformUser();
return;
}
}
or just:
SomeFunction()
{
try { // No fail early anymore IMHO, because you could fail before calling DoSomethingWith(value)
DoSomethingWith(value);
} catch (ArgumentNullException) {
InformUser();
return;
}
}
?
This is a very general question and the right solution depends on the specific code and architecture.
Generally regarding error handling
The main focus should be to catch the exception on the level where you can handle it.
Handling the exceptions at the right place makes the code robust, so the exception doesn't make the application fail and the exception can be handled accordingly.
Failing early makes the application robust, because this helps avoiding inconsistent states.
This also means that there should be a more general try catch block at the root of the execution to catch any non fatal application error which couldn't be handled. Which often means that you as a programmer didn't think of this error source. Later you can extend your code to also handle this error. But the execution root shouldn't be the only place where you think of exception handling.
Your example
In your example regarding ArgumentNullException:
Yes, you should fail early. Whenever your method is invoked with an invalid null argument, you should throw this exception.
But you should never catch this exception, cause it should be possible to avoid it. See this post related to the topic: If catching null pointer exception is not a good practice, is catching exception a good one?
If you are working with user input or input from other systems, then you should validate the input. E.g. you can display validation error on the UI after null checking without throwing an exception. It is always a critical part of error handling how to show the issues to users, so define a proper strategy for your application. You should try to avoid throwing exceptions in the expected program execution flow. See this article: https://msdn.microsoft.com/en-us/library/ms173163.aspx
See general thoughts about exception handling below:
Handling exceptions in your method
If an exception is thrown in the DoSomethingWith method and you can handle it and continue the flow of execution without any issue, then of course you should do those.
This is a pseudo code example for retrying a database operation:
void DoSomethingAndRetry(value)
{
try
{
SaveToDatabase(value);
}
catch(DeadlockException ex)
{
//deadlock happened, we are retrying the SQL statement
SaveToDatabase(value);
}
}
Letting the exception bubble up
Let's assume your method is public. If an exception happens which implies that the method failed and you can't continue execution, then the exception should bubble up, so that the calling code can handle it accordingly. It depends one the use-case how the calling code would react on the exception.
Before letting the exception bubble up you may wrap it into another application specific exception as inner exception to add additional context information. You may also process the exception somehow, E.g log it , or leave the logging to the calling code, depending on your logging architecture.
public bool SaveSomething(value)
{
try
{
SaveToFile(value);
}
catch(FileNotFoundException ex)
{
//process exception if needed, E.g. log it
ProcessException(ex);
//you may want to wrap this exception into another one to add context info
throw WrapIntoNewExceptionWithSomeDetails(ex);
}
}
Documenting possible exceptions
In .NET it is also helpful to define which exceptions your method is throwing and reasons why it might throw it. So that the calling code can take this into consideration. See https://msdn.microsoft.com/en-us/library/w1htk11d.aspx
Example:
/// <exception cref="System.Exception">Thrown when something happens..</exception>
DoSomethingWith(value)
{
...
}
Ignoring exceptions
For methods where you are OK with a failing method and don't want to add a try catch block around it all the time, you could create a method with similar signature:
public bool TryDoSomethingWith(value)
{
try
{
DoSomethingWith(value);
return true;
}
catch(Exception ex)
{
//process exception if needed, e.g. log it
ProcessException(ex);
return false;
}
}
I have a helper method which encrypts some data on the iPhone. If the operatin is interrupted because the device gets locked, I want to delete the file I have just been processing. Therefore I add a notifiaction listsner if the method is called.
Two issues:
1. I get a warning that the method I use to add the listener is obsolete. How else would I do it?
2. If processing is done I would like to get rid of the listener - but how?
private static foo(string sDestPathAndFile)
{
NSNotificationCenter.DefaultCenter.AddObserver ( "UIApplicationProtectedDataWillBecomeUnavailable",
delegate( NSNotification oNotification )
{
Util.DeleteFile ( sDestPathAndFile );
throw new InvalidOperationException ( "Protected data became unavailable - device locked?" );
} );
// Do some processing here.
// ...
// Now get rid of the notification listener - but how?
}
To get rid of the obsolete warning, you should use the following:
NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.ProtectedDataWillBecomeUnavailable, Handler);
This applies to all observers, e.g.:
UIKeyboard.WillHideNotification
UIKeyboard.WillShowNotification
UIDevice.OrientationDidChangeNotification
and so on. These are the appropriate NSString's that NSNotificationCenter is expecting.
As for getting rid of it, I can't verify this first hand as I'm currently not in a position to do so but one possible way is:
Declare the addobserver as an NSObject, then use the NSNotificationCenter.DefaultCenter.RemoveObserver to remove it:
NSObject obj = NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.ProtectedDataWillBecomeUnavailable, handler);
// do whatever you need to do
// time to remove:
NSNotificationCenter.DefaultCenter.RemoveObserver(obj);