Avoid exception causes to stop Mono.zip immediately - project-reactor

Is it possible to avoid that if one mono in mono.zip throws exception all other monos are stopping immediately? I want them to end normally and perhaps to handle the erroneous one by something like „.doOnError“ or „.continueOnError. Is that a way to go?
Regards
Bernado

Yes, it's possible. You can use Mono.zipDelayError. As you can understand from the method's name, it delays errors from the Monos. If several Monos error, their exceptions are combined.
If you have to get the combined result anyway, zipDelayError is not the solution. Use the zip operator and handle the error case with a fallback operator like onErrorResume or retry on the zipped Mono or any upstream one.

I stated that my question is answered but it is not yet. The following example states my case: some mono will fail, but i want the result as the error too. i expected the follwoing code as to run to completion but it fails:
Mono<String> error = Mono.error(new RuntimeException());
error = error.onErrorResume(throwable -> Mono.just("hell0"));
Mono<String> test = Mono.just("test");
Mono<String> test1 = Mono.just("test1");
Mono<String> test2 = Mono.just("test2");
List<Mono<String>> monolist = new ArrayList<>();
monolist.add(test);
monolist.add(test1);
monolist.add(test2);
monolist.add(error);
Mono<Long> zipDelayError = Mono.zipDelayError(monolist, arrayObj -> Arrays.stream(arrayObj).count());
System.out.println(zipDelayError.block());

Related

OWLKnowledgeExplorerReasoner - getObjectLabel always ends in error Unreachable situation

I am trying to access information about completion graph, but everytime it ends with error uk.ac.manchester.cs.jfact.helpers.UnreachableSituationException: Unreachable situation! when I call getObjectLabel(rootNode, false/true). I was trying it on every class expression from the ontology but always ended up with the error message.
Set<OWLClassExpression> types = classSet2classExpSet(hybridSolver.ontology.classesInSignature().collect(toSet()));
for (OWLClassExpression e : types) {
OWLKnowledgeExplorerReasoner.RootNode rootNode = loader.getReasoner().getRoot(e);
System.out.println(loader.getReasoner().getObjectLabel(rootNode, false)); //problem UnreachableSituation !!
Node<OWLObjectProperty> propertyNode = (Node<OWLObjectProperty>) loader.getReasoner().getObjectNeighbours(rootNode, false);
for (OWLObjectProperty p : propertyNode.getEntities()) {
Collection<OWLKnowledgeExplorerReasoner.RootNode> rootNodes = loader.getReasoner().getObjectNeighbours(rootNode, p);
...
}
}
Other method getObjectNeighbours(rootNote, false) works fine.
Can somebody help? Is there any way to access completion graph with OWLAPI? Why it might end with this error?
The labels found for the nodes in question are not named class expressions (e.g., they are AND nodes. These cannot be translated back to OWLClass and there's no current implementation for translating back class expressions.
Tweaking the code to remove the exceptions is doable but for your ontology example you'd always get back empty nodes, which isn't very informative.
I have removed the exception throwing in the latest version 5 branch, however I doubt this is sufficient for your needs.

Q: Using Circuit Breaker in SAP Cloud SDK resilience

When I tried to use ResilienceDecorator.executeCallable() to enable circuit breaker, I have to throw out ResilienceRuntimeException in my callable to make the circuit break work. Sample code as below. Without it, circuit breaker is always closed. is this the right way to do it?
response = ResilienceDecorator.executeCallable(() -> {
HttpResponse response1 = tryHttpClient.get().execute(request);
if (response1.getStatusLine().getStatusCode() == 404){
throw new ResilienceRuntimeException("404 error is raised when calling SB api");
}
return response1;
},
ResilienceConfiguration.of(SubscriptionBillingAdapter.class).isolationMode(ResilienceIsolationMode.TENANT_OPTIONAL).timeLimiterConfiguration(ResilienceConfiguration.TimeLimiterConfiguration.of().timeoutDuration(Duration.ofSeconds(6L))).circuitBreakerConfiguration(ResilienceConfiguration.CircuitBreakerConfiguration.of().waitDuration(Duration.ofSeconds(600000L)).failureRateThreshold(1).closedBufferSize(1).halfOpenBufferSize(1)),
e -> {LOG.warn("resiliience fallback call: " + e); return response1;});
I am asking since I don't see any document of it. Also when I check how destination configuration in SCP is retrieved, I saw the following code in com.sap.cloud.sdk.cloudplatform.connectivity.DestinationService . It doesn't throw out ResilienceRuntimeException, when using ResilienceDecorator.executeCallable(). so my question is do I need to throw out ResilienceRuntimeException or not to make circuit breaker work? if I don't need, anything wrong in my code?
return (String)ResilienceDecorator.executeCallable(() -> {
XsuaaCredentials xsuaaCredentials = (new ServiceCredentialsRetriever()).getClientCredentials("destination");
AccessToken accessToken;
if (propagateUser) {
accessToken = xsuaaService.retrieveAccessTokenViaUserTokenExchange(xsuaaCredentials.getXsuaaUri(), xsuaaCredentials.getCredentials(), useProviderTenant);
} else {
accessToken = xsuaaService.retrieveAccessTokenViaClientCredentialsGrant(xsuaaCredentials.getXsuaaUri(), xsuaaCredentials.getCredentials(), useProviderTenant);
}
return this.fetchDestinationsJson(servicePath, accessToken);
}, ResilienceConfiguration.of(DestinationService.class).isolationMode(ResilienceIsolationMode.TENANT_OPTIONAL).timeLimiterConfiguration(TimeLimiterConfiguration.of().timeoutDuration(Duration.ofSeconds(6L))).circuitBreakerConfiguration(CircuitBreakerConfiguration.of().waitDuration(Duration.ofSeconds(6L))));
Steven
I'm not the most experienced in this specific part, but looking at your code it seems fine to me. When a server returns 404 Not found it's not an indication of a service failure or error, but that resource is simply not found. If in your case 404 means that an error took place and the request has to be retried with a resilient approach, you have to throw that exception to inform Resilience4J that smth went wrong.
While we're working on improving our documentation, I recommend you take a look at the existing tutorial explaining resilience within the SAP Cloud SDK context. There we also throw ResilienceRuntimeException for clarity:
public List<BusinessPartner> execute() {
return ResilienceDecorator.executeSupplier(this::run, myResilienceConfig, e -> {
logger.warn("Fallback called because of exception.", e);
return Collections.emptyList();
});
}
private List<BusinessPartner> run() {
try {
return businessPartnerService
.getAllBusinessPartner()
.select(BusinessPartner.BUSINESS_PARTNER,
BusinessPartner.LAST_NAME,
BusinessPartner.FIRST_NAME,
BusinessPartner.IS_MALE,
BusinessPartner.IS_FEMALE,
BusinessPartner.CREATION_DATE,
BusinessPartner.TO_BUSINESS_PARTNER_ADDRESS
.select(BusinessPartnerAddress.CITY_NAME,
BusinessPartnerAddress.COUNTRY,
BusinessPartnerAddress.TO_EMAIL_ADDRESS
.select(AddressEmailAddress.EMAIL_ADDRESS)
)
)
.filter(BusinessPartner.BUSINESS_PARTNER_CATEGORY.eq(CATEGORY_PERSON))
.orderBy(BusinessPartner.LAST_NAME, Order.ASC)
.top(200)
.execute(destination);
} catch (ODataException e) {
throw new ResilienceRuntimeException(e);
}
}
Regarding the code snippet from the DestinationService, I believe that fetchDestinationsJson() method throws an implicit exception thus letting Resilience4J know that smth went wrong. While in your case HttpClient won't throw anything when receiving 404 as it's a correct response code as any other.
I also think that checking CircuitsBreaker examples from Resilience4J library might be helpful.
I hope it helps:)
No you do not have to throw a ResilienceRuntimeException. In fact the SDK only uses that to wrap checked and unchecked exceptions into an unchecked exception which wraps all kinds of failures that occur within a resilient call.
Please expand your question with more details, I'll then expand this answer:
Which version of the SDK are you using?
How (and how often) do you invoke the decorated callable? Please expand the code block.
Please specify the exact behaviour you observe. What exception is thrown when you invoke the decorated callable? If the circuit breaker opens this should be a CallNotPermittedException wrapped inside a ResilienceRuntimeException
Reduce the callable to simply throw an exception in order to simplify the code
Reduce the resilience configuration to only use a circuit breaker (leverage ResilienceConfiguration.empty()). If that works add stuff back in again until it doesn't.
For reference also please find the documentation of resilience4j which the SDK uses under the hood to perform resilient operations.

How to transform a Mono to a Mono<Void> in case of error

I'm trying to write a method that does something like this
Mono<A> ma = networkCall(); //this might fail
Mono<Void> mv = ma.map( a -> ....) #some logic to perform with `A`
return mv;
The trick is, ma might very well fail and then I would want to just log the situation and return a Mono<Void> that completes with no error.
Looking at the Mono api I just found onErrorResume or onErrorReturn but both would take a function that returns an A (which I can't fabricate), while I would like to return a Void.
I would imagine the solution is quite simple, but couldn't quite find the right operations for this.
So, what operations should I apply to ma to transform it into a Mono<Void> in case of error?
I just found onErrorResume or onErrorReturn but both would take a function that returns an A
onErrorReturn() indeed requires you to return an A, but onErrorResume() just requires you to return a Mono<A>, which can be empty.
So you can use:
doOnNext() to perform your logic with A if the call is successful;
doOnError() to log your error if the call is not successful;
onErrorResume() to return an empty result
then() to convert the result into a Mono<Void>.
Something like:
networkCall()
.doOnNext(a -> doSomethingWith(a))
.doOnError(e -> e.printStackTrace())
.onErrorResume(e -> Mono.empty())
.then();

How to get try / catch to work in erlang

i'm pretty new to erlang and i'm trying to get a basic try / catch statement to work. I"m using webmachine to process some requests and all i really want to do is parse some JSON data and return it. In the event that the JSON data is invalid, I just want to return an error msg. Here is the code I have so far.
(the JSON data is invalid)
to_text(ReqData, Context) ->
Body = "{\"firstName\": \"John\"\"lastName\": \"Smith\"}",
try decode(Body) of
_ -> {"Success! Json decoded!",ReqData,Context}
catch
_ -> {"Error! Json is invalid",ReqData,Context}
end.
decode(Body) ->
{struct, MJ} = mochijson:decode(Body).
The code compiles, but when i run it, and send a request for the text, i get the following error back.
error,{error,{case_clause,{{const,"lastName"},
": \"Smith\"}",
{decoder,utf8,null,1,31,comma}}},
[{mochijson,decode_object,3},
{mochijson,json_decode,2},
{webmachine_demo_resource,test,1},
{webmachine_demo_resource,to_text,2},
{webmachine_demo_resource,to_html,2},
{webmachine_resource,resource_call,3},
{webmachine_resource,do,3},
{webmachine_decision_core,resource_call,1}]}}
What exactly am i doing wrong? documentation says the "catch" statement handles all errors, or do i have to do something to catch a specific error that is thrown by mochijson:decode.
Please any leads or advice would be helpful. Thanks.
The catch-clause _ -> ... only catches exceptions of the 'throw' class. To catch other kinds of exceptions, you need to write a pattern on the form Class:Term -> ... (i.e., the default Class is throw). In your case:
catch
_:_ -> {"Error! Json is invalid", ReqData, Context}
end
When you do this, you should always ask yourself why you're catching every possible exception. If it's because you're calling third-party code that you don't know how it might behave, it's usually OK. If you're calling your own code, remember that you're basically throwing away all information about the failure, possibly making debugging a lot more difficult. If you can narrow it down to catching only particular expected cases and let any other exceptions fall through (so you see where the real failure occurred), then do so.

F# async web request, handling exceptions

I'm trying to use async workflows in F# to fetch several web requests.
However, some of my requests are occasionally returning errors (e.g. http 500), and I don't know how to handle this. It appears like my F# program gets stuck in an infinite loop when running in the debugger.
I'm probably missing some stuff, cause examples I seen didn't compile out of the box. First thing I found that helped was this bit of code:
type System.Net.WebRequest with
member req.GetResponseAsync() =
Async.BuildPrimitive(req.BeginGetResponse, req.EndGetResponse)
and then I have my bit of code to fetch the requests, which is pretty standard from examples I've seen:
let async_value = async {
let req = WebRequest.Create(url)
let! rsp = req.GetResponseAsync()
return (rsp :?> HttpWebResponse).StatusCode
}
and then I try to get the result:
let status = Async.RunSynchronously(async_value)
But when I run my program in debugger, it breaks at req.EndGetResponse because server returned internal server error 500. If I keep just continuing execution, it gets in a funky loop, breaking at req.EndGetResponse (sometimes several in a row), and at let status = Async.RunSynchronously(async_value).
How do I get around the exception problem so I can get my status code? Also, do I need the type thing I did above? Or am I missing some library/dll for F#/VS 2010 Beta 1, of which this is already a part of?
I actually run several requests in parallel, using Async.RunSynchronously(Async.Parallel(my_array_of_async_values)), though I don't think that is related to the exception issue I'm having.
The fact the examples I've come across only use Async.Run rather than Async.RunSynchronously is probably an indicator I'm missing something... =/
It's now called 'AsyncGetResponse' (no longer 'GetResponseAsync'). And 'Run' was renamed to 'RunSynchronously'. So I don't think you're missing anything substantial here, just name changes in the latest release.
What are your debugger settings with regard to "Tools\Options\Debugging\General\Enable Just My Code" and "Debug\Exceptions" (e.g. set to break when any first-chance CLR exception is thrown or not)? I am unclear if your question involves the program behavior, or the VS tooling behavior (sounds like the latter). This is further confounded by the fact that breakpoint/debugging 'locations' in F# Beta1 have some bugs, especially regarding async workflows, which means that the behavior you see in the debugger may look a little strange even if the program is executing properly...
Are you using VS2008 CTP or VS2010 Beta1?
In any case, it appears the exception due to a 500 response is expected, this is how WebRequest works. Here's a short demo program:
open System
open System.ServiceModel
open System.ServiceModel.Web
[<ServiceContract>]
type IMyContract =
[<OperationContract>]
[<WebGet(UriTemplate="/Returns500")>]
abstract Returns500 : unit -> unit
[<OperationContract>]
[<WebGet(UriTemplate="/Returns201")>]
abstract Returns201 : unit -> unit
type MyService() =
interface IMyContract with
member this.Returns500() =
WebOperationContext.Current.OutgoingResponse.StatusCode <-
System.Net.HttpStatusCode.InternalServerError
member this.Returns201() =
WebOperationContext.Current.OutgoingResponse.StatusCode <-
System.Net.HttpStatusCode.Created
let addr = "http://localhost/MyService"
let host = new WebServiceHost(typeof<MyService>, new Uri(addr))
host.AddServiceEndpoint(typeof<IMyContract>, new WebHttpBinding(), "") |> ignore
host.Open()
open System.Net
let url500 = "http://localhost/MyService/Returns500"
let url201 = "http://localhost/MyService/Returns201"
let async_value (url:string) =
async {
let req = WebRequest.Create(url)
let! rsp = req.AsyncGetResponse()
return (rsp :?> HttpWebResponse).StatusCode
}
let status = Async.RunSynchronously(async_value url201)
printfn "%A" status
try
let status = Async.RunSynchronously(async_value url500)
printfn "%A" status
with e ->
printfn "%s" (e.ToString())
You can use try...with inside the async to catch exceptions:
let async_value =
async {
let req = WebRequest.Create("http://unknown")
try
let! resp = req.AsyncGetResponse()
return "success"
with
| :? WebException as e -> return "failure"
}

Resources