I am looking at some legacy C# code like this:
await Task.Run(() =>
{
_logger.LogException(LogLevel.Error, message, exception);
Thread.Sleep(500);
});
I created the following F# code but the Thread.Sleep is not getting hit:
Tasks.Task.Run(fun _ -> logger.Log(LogLevel.Warn, message)
Thread.Sleep(500))
Can someone tell me what I am doing wrong? I need maintain the method's signature.
Thanks in advance.
This is normally where you would use a asynchronous workflow. If you need to keep the function returning a Task, you can do this:
let someFunc (message : string) : Task =
async {
logger.Log(LogLevel.Warn, message)
Thread.Sleep(500)
} |> Async.StartAsTask :> Task
Looks like it is working, I am just getting an exception:
System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. This can happen if the test(s) started a thread but did not stop it. Make sure that all the threads started by the test(s) are stopped before completion.
Related
I am trying out the Future with async await for asynchronous programming.
The code i tested is a simple Future.
//order a new coffee perhaps!
Future<String> order(String newOrder){
final String Function() func = ()=> "${newOrder} is requested!";
final _order = Future.delayed(Duration(seconds: 5),func);
return _order;
}
When i run this code like a promise.
order("promised order")
.then((result) => print(result))
.catchError((err){
print(err.error);
});
This behaves like a asynchronous non-blocking code
However the same code when i run it with async/await behaves like a synchronous code and blocks all the other code, it waits 5 secs to run the next line.
void main(List<String> arguments) async {
final _myOrder = await order('Lattee mocha');
print(_myOrder);
//...all the other code waits for
}
So i thought async/await is same as futures, where non-blocking..
How come it blocks the other code execution ?
The whole point of the async/await pattern is to wait (hence await) until the Future completes and only then continue with this code execution.
Think of it as a way to not have endless .then() chains and much simplified error handling.
If you want to not wait, then you just leave out the await keyword. Obviously, if you don't (a)wait, you don't get the result.
You can still use classic .then() chains when it suits your purpose better in your program.
What people talk about when they say "non blocking" they mean that when the compiler sees the await keyword, it knows to keep the rest of the program, the event loops, animations etc running and not block the complete program.
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.
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());
Should I use taskThatReturns.Wait() in code below or I can omit it since according to my understanding taskThatReturns.Result will do wait anyway.
Task<string> taskThatReturns = new Task<string>(MethodThatReturns);
taskThatReturns.Start();
taskThatReturns.Wait();
Console.WriteLine(taskThatReturns.Result);
The call of Wait() before accessing Result is unnecessary.
Examination of the reference code of Task and Task<TResult> shows that both the void Wait() method and the getter of the Result property eventually make their way into the method that does the actual waiting:
internal bool InternalWait(int millisecondsTimeout, CancellationToken cancellationToken)
Both code paths send identical parameter values to InternalWait - infinite wait and default cancellation token.
If you call Wait before accessing Result, the code path inside the getter leading to InternalWait would be skipped, because the task is known to be completed. However, the net result would remain the same in both cases.
Note: This answer intentionally ignores opportunities to optimize your code fragment.
async void DoTask() {
string task = await returnString();
Console.WriteLine(task);
}
Task<string> returnString() {
// you code here
}
You can use async method to await Task execution
To answer the actual question. You either need to wait to get the results, or you need to do as Panagiotis Kanavos suggested, and await a task. You're overcomplicating threading, a common issue with all the bad examples out there.
If you still want to use Task better approach is:
var result = taskThatReturns.GetAwaiter().GetResult();
I want to receive data (simply as a string) from the client-web side to update the database, but it's a bit lock for me now, so first write the data to a file in the drive with using System.IO.File.WriteAllText(#"my-file.txt")
I got that error
error FS9001: Method name not found in JavaScript compilation: (receive : System.Object -> unit)
Can you tell me where I did wrong and fix it?
Remoting.fs
Client.fs
Main.fs
WebSharper's client side can call methods that are themselves in [<JavaScript>] scope or marked [<Remote>] for remote calls. The error message is not mentioning the second option, but that is what you need here (same as the sample function DoSomething has it too).
You will also need to make the remote function to not send over an obj but a string. Remote function arguments are deserialized based on type information and cannot be obj. For example in client code, use Server.receive rvInput.Value. (rvInput is a reactive variable for which .Value contains current value)
Note that if you want to return a value to the server, the remote function must be an async. Here, just for logging, returning unit works too, but then you have no way on the server to determine if the logging was successful. By returning an async<unit>, you can catch errors in the client code if you want to guard against connection or server errors. Again, the sample code in the template gives some guidance.
(Cross posting from http://forums.websharper.com/topic/84579)
Here is what your server-side function should look like:
[<Remote>]
let Receive (input: string) =
async {
System.IO.File.WriteAllText(#"D:/myDatabase.txt", "Server received data: " + input)
}
and to call it from Client.fs, you need:
...
button [
on.click (fun _ _ ->
async {
do! Server.Receive rvInput.Value
} |> Async.Start
)
] [text "Receive"]
...