How to Force an Exception from a Task to be Observed in a Continuation Task? - .net-4.0

I have a task to perform an HttpWebRequest using
Task<WebResponse>.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)
which can obviously fail with a WebException. To the caller I want to return a Task<HttpResult> where HttpResult is a helper type to encapsulate the response (or not). In this case a 4xx or 5xx response is not an exception.
Therefore I've attached two continuations to the request task. One with TaskContinuationOptions OnlyOnRanToCompletion and the other with OnlyOnOnFaulted. And then wrapped the whole thing in a Task<HttpResult> to pick up the one result whichever continuation completes.
Each of the three child tasks (request plus two continuations) is created with the AttachedToParent option.
But when the caller waits on the returned outer task, an AggregateException is thrown is the request failed.
I want to, in the on faulted continuation, observe the WebException so the client code can just look at the result. Adding a Wait in the on fault continuation throws, but a try-catch around this doesn't help. Nor does looking at the Exception property (as section "Observing Exceptions By Using the Task.Exception Property" hints here).
I could install a UnobservedTaskException event handler to filter, but as the event offers no direct link to the faulted task this will likely interact outside this part of the application and is a case of a sledgehammer to crack a nut.
Given an instance of a faulted Task<T> is there any means of flagging it as "fault handled"?
Simplified code:
public static Task<HttpResult> Start(Uri url) {
var webReq = BuildHttpWebRequest(url);
var result = new HttpResult();
var taskOuter = Task<HttpResult>.Factory.StartNew(() => {
var tRequest = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
webReq.EndGetResponse,
null, TaskCreationOptions.AttachedToParent);
var tError = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestError(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnFaulted);
var tSuccess = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestSuccess(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnRanToCompletion);
return result;
});
return taskOuter;
}
with:
private static HttpDownloaderResult HandleWebRequestError(
Task<WebResponse> respTask,
HttpResult result) {
Debug.Assert(respTask.Status == TaskStatus.Faulted);
Debug.Assert(respTask.Exception.InnerException is WebException);
// Try and observe the fault: Doesn't help.
try {
respTask.Wait();
} catch (AggregateException e) {
Log("HandleWebRequestError: waiting on antecedent task threw inner: "
+ e.InnerException.Message);
}
// ... populate result with details of the failure for the client ...
return result;
}
(HandleWebRequestSuccess will eventually spin off further tasks to get the content of the response...)
The client should be able to wait on the task and then look at its result, without it throwing due to a fault that is expected and already handled.

In the end I took the simplest route I could think of: hide the exception. This is possible because WebException has a property Response which gives access to the HttpWebResponse I want:
var requestTask = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
ia => {
try {
return webReq.EndGetResponse(ia);
} catch (WebException exn) {
requestState.Log(...);
return exn.Response;
}
});
And then handle errors, redirects and success responses in the continuation task.

Related

Mono.zip request fails when subscribed

I have the following piece of code, where externalgetcall is a GET request to a external service asking for some data
myservice.externalgetcall(id).blockOptional();
this code works, but if i get rid of the blockOptional and write the following, externalgetcall fails with a java.lang.NullPointerException:
java.lang.NullPointerException: null
at org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository.saveAuthorizedClient(HttpSessionOAuth2AuthorizedClientRepository.java:63) ~[spring-security-oauth2-client-5.7.2.jar:5.7.2]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ? Request to GET
myservice.externalgetcall(id).subscribe();
moreover, if I do this, the blocking one right before the non blocking one, it works, so it clearly has to do with Oauth not completing somehow if the call is non blocking:
myservice.externalgetcall(id).blockOptional();
myservice.externalgetcall(id).subscribe();
externalgetcall(id)
public Mono<MyClass> externalgetcall(String id) {
logger.debug("getting contact: {}", id);
return this.webClient
.get()
.uri(externaluri)
.retrieve()
.bodyToMono(MyClass.class)
.doOnNext(myClass -> logger.debug("success {}", myClass))
.doOnError(throwable -> logger.error("error : ", throwable))
}
it fails at this point:
it looks like it happens when trying to run the setAttribute method,when debugging i can see this:
this = {FluxSubscribeOnCallable$CallableSubscribeOnSubscription#13199} size = 1
Unable to evaluate the expression Method threw 'java.lang.UnsupportedOperationException' exception.
public final class HttpSessionOAuth2AuthorizedClientRepository implements OAuth2AuthorizedClientRepository {
private static final String DEFAULT_AUTHORIZED_CLIENTS_ATTR_NAME = HttpSessionOAuth2AuthorizedClientRepository.class.getName() + ".AUTHORIZED_CLIENTS";
private final String sessionAttributeName;
public HttpSessionOAuth2AuthorizedClientRepository() {
this.sessionAttributeName = DEFAULT_AUTHORIZED_CLIENTS_ATTR_NAME;
}
public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal, HttpServletRequest request, HttpServletResponse response) {
if (this.isPrincipalAuthenticated(principal)) {
this.authorizedClientService.saveAuthorizedClient(authorizedClient, principal);
} else {
this.anonymousAuthorizedClientRepository.saveAuthorizedClient(authorizedClient, principal, request, response);
}
}
public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal, HttpServletRequest request, HttpServletResponse response) {
Assert.notNull(authorizedClient, "authorizedClient cannot be null");
Assert.notNull(request, "request cannot be null");
Assert.notNull(response, "response cannot be null");
Map<String, OAuth2AuthorizedClient> authorizedClients = this.getAuthorizedClients(request);
authorizedClients.put(authorizedClient.getClientRegistration().getRegistrationId(), authorizedClient);
request.getSession().setAttribute(this.sessionAttributeName, authorizedClients);
}
This is not much context to come to a rock-solid explanation, but the NPE leads me to believe that this is a case of race condition.
Something to consider is the fact that you are replacing a blocking terminal operation with an asynchronous terminal operation on the publisher. blockOptional and subscribe both initiate a subscription, but in the latter case, execution will not wait at that point for the publisher's onComplete signal.
Again, hard to tell without the complete code, but my guess is that whatever code comes after this snippet is using some data that is populated or hydrated as a result of this publisher. Using blockOptional ensures that the publisher completes before this happens, while subscribe does not.

Efficient thread use on high traffic ASP.NET Core Web API with processing timeout

My ASP.NET Core Web API (Linux) endpoint needs to serve a high volume of concurrent requests. If the request takes more than 200ms then it should abort and return a custom piece of JSON. The code is all awaitable. The request must always return HTTP 200 and the HTTP request timeout cannot be reduced from 30 secs to 200ms.
What is the most efficient way to accomplish what I want? Should I use a Task? Should I use Task.Wait or Task.WaitAsync? Or should the work methods run in the HTTP request thread, periodically check Stopwatch.Elapsed and throw a timeout exception?
This is my current code:
var task = Task.Factory.StartNew(async () =>
{
// Processing part 1
var result1 = await DoWorkPart1("Param1");
if (cancellationToken.IsCancellationRequested())
cancellationToken.ThrowIfCancellationRequested();
// Processing part 2
var result2 = wait DoWorkPart2(result1);
return result2;
}).Unwrap(); // Return lambda task, not outer task
// Is it better to use WaitAsync?
task.Wait(TimeSpan.FromMilliseconds(150));
if (task.IsCompleted) // Result within timeout
{
if (task.Exception == null) // Success
{
return Ok(task.Result);
}
else
{
return Ok(new FailedObject() { Reason = ReasonEnum.UnexpectedError };
}
}
else // Timeout
{
return OK(new FailedObject() { Reason = ReasonEnum.TookTooLong };
}
What is the most efficient way to accomplish what I want?
I recommend using CancellationTokens to cancel. With a very short timeout like 200ms, you might just want to create a CancellationTokenSource with that timeout and ignore the CancellationToken provided to you by ASP.NET, which handles situations like clients disconnecting early.
Should I use a Task? Should I use Task.Wait or Task.WaitAsync? Or should the work methods run in the HTTP request thread, periodically check Stopwatch.Elapsed and throw a timeout exception?
I would say none of these. Instead, pass the CancellationToken down as far as you possibly can, ideally right to the lowest-level APIs your asynchronous code is calling.
If some of those APIs ignore their cancellation tokens, or if it's possible they may complete synchronously (e.g., due to caching), then adding cancellationToken.ThrowIfCancellationRequested(); in-between steps is a good idea.
Side note: Don't use StartNew.
using var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(200));
try
{
// Processing part 1
var result1 = await DoWorkPart1("Param1", cts.Token);
cts.Token.ThrowIfCancellationRequested();
// Processing part 2
var result2 = wait DoWorkPart2(result1, cts.Token);
return Ok(result2);
}
catch (OperationCanceledException)
{
return OK(new FailedObject() { Reason = ReasonEnum.TookTooLong };
}
catch
{
return Ok(new FailedObject() { Reason = ReasonEnum.UnexpectedError };
}

Catching errors on actor construction in Akka TestKit

I am trying to learn unit testing with Akka.
I have a situation where one of my tests was throwing an exception on construction and was wondering what the best way to capture this and log or otherwise throw it would be. As it stands now I had to attach a debugger and see where it threw.
I thought that I could perhaps create another actor which does logging and, on error, have a message sent to it. Breakpoints I put in the ErrorActor were never hit though. It seems as though the RootActor failed and timed out before the message was sent / received.
Is there something I'm doing wrong here or am I fundamentally off base with this? What is the the recommended way to catch errors in unit tests?
Thanks very much
[Fact]
public void CreateRootActor()
{
// Arrange
var props = Props.Create(() => new RootActor());
Sys.ActorOf(Props.Create( () =>new TestErrorActor(TestLogger)), ActorPaths.ErrorActor.Name); // register my test actor
// Act
var actor = new TestActorRef<RootActor>(this.Sys, props);
// Assert
Assert.IsType<RootActor>(actor.UnderlyingActor);
}
public class RootActor : ReceiveActor
{
private ITenantRepository tenantRepository;
public RootActor(ILifetimeScope lifetimeScope)
{
try
{
this.tenantRepository = lifetimeScope.Resolve<ITenantRepository>(); // this throws
}
catch (Exception e)
{
Context.ActorSelection(ErrorActor.Name).Tell(new TestErrorActor.RaiseError(e));
throw;
}
....
I got around this by using Akka.Logger.Serilog and a try / catch in the RootActor. I deleted the ErrorActor.

How to check if async/await really async?

I have built a certain application( service ) based on async/await new keywords in c# 5.0 using WebApi which it self cool, I have create a call from Oracle db Http_Request, but i have tested and it's not really feels right, how can I unit test the async matter if this?
public async Task<WebResponse> Post(Customer customer)
{
if (!customer.ReturnSuccess()) throw new ArgumentNullException("customer");
_logger.Info(string.Format("Customer validation request - date = {0} \n {1}\t\n", DateTime.Now, customer));
try
{
return await Task.Factory.StartNew(() => _service.EvaluateCustomer(customer));
}
catch (Exception e)
{
_logger.ErrorException("Error", e);
}
return null;
}
Do not Unit Test language features - they are already tested by someone who has much more money than you. Test your business logic instead.
Read msdn about async/await behaviour here:
http://msdn.microsoft.com/en-us/library/vstudio/hh156513.aspx
The method runs synchronously until it reaches its first await
expression, at which point the method is suspended until the awaited
task is complete. In the meantime, control returns to the caller of
the method, as the example later in this topic shows.
I agree with Cheburek in general: don't waste your time unit testing things like await and Task.Run.
However, if you want to ensure your method is properly waiting for EvaluateCustomer, then you inject a service that is under your control and ensure Post only completes after EvaluateCustomer completes:
[TestMethod]
public async Task PostWaitsForEvaluateCustomer()
{
var finishEvaluateCustomer = new ManualResetEvent(false);
var service = new MyFakeService(finishEvaluateCustomer)
{
EvaluateCustomer = _ => finishEvaluateCustomer.WaitOne();
};
var objectUnderTest = new MyObject(service);
Task postTask = objectUnderTest.Post(..);
Assert.IsFalse(postTask.IsCompleted);
finishEvaluateCustomer.Set();
await postTask;
}

How to prevent transaction scope from throwing an exception I have already handled?

I've got a WCF operation conceptually like this:
[OperationBehavior(TransactionScopeRequired = true)]
public void Foo()
{
try { DAL.Foo(); return Receipt.CreateSuccessReceipt(); }
catch (Exception ex) { return Receipt.CreateErrorReceipt(ex); }
}
If something goes wrong (say, foreign key constraint violaion) in executing the DAL code, control passes to the catch block as I'd expect. But when the method returns, it seems the transaction scope has sniffed out that the transaction failed, and it decides it better throw an exception to make sure to notify the caller about it.
In turn my client application does not get the receipt I want to return, but rather an exception:
System.ServiceModel.FaultException:
The transaction under which this method call was executing was asynchronously aborted.
What is wrong with my design?
I could have the service not catch anything, but this has it's own problems as the service needs to use exception shielding and the client (a batch tool internal to the system) needs to log the error information. The service logs errors too, but not in the same way and to the same place as the batch.
Be careful here! If you set TransactionAutoComplete=true then if the service returns normally the transaction will be committed. Only if there is an unhandled exception (which for the most part you don't have because you are catching exceptions and returning a receipt message) will the transaction be rolled back. See http://msdn.microsoft.com/en-us/library/system.servicemodel.operationbehaviorattribute.transactionautocomplete.aspx.
Think about a scenario where you successfully executed some DAL calls but some other exception (e.g. NullReferenceException) occurs. Now the transaction will be committed when the method completes because no unhandled exception has occurred but the client receives an ErrorReceipt.
For your scenario, I think you will have to manage the transactions yourself. For example:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public Receipt Foo()
{
// Create TransactionScope using the ambient transaction
using (var scope = new TransactionScope() )
{
try { DAL.Foo(); return Receipt.CreateSuccessReceipt(); scope.Complete(); }
catch (Exception ex) { return Receipt.CreateErrorReceipt(ex); }
}
}
You could eliminate boilerplate code by creating a helper method that wraps it all within the transaction or you could use policy injection/interception/aspects to manage transactions.
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public Receipt Foo()
{
return ProcessWithTransaction(() =>
{
DAL.Foo();
return Receipt.CreateSuccessReceipt();
}
, (ex) =>
{
return Receipt.CreateErrorReceipt(ex);
}
);
}
T ProcessWithTransaction<T>(Func<T> processor, Func<Exception, T> exceptionHandler)
{
using (var scope = new TransactionScope())
{
try
{
T returnValue = processor();
scope.Complete();
return returnValue;
}
catch (Exception e)
{
return exceptionHandler(e);
}
}
}
You mention that you need to use exception shielding. If you are not averse to throwing faults when an error occurs then you could use Enterprise Library Exception Handling Block's exception shielding which also lets you log the information on the way out (if you desire).
If you decided to go that route your code would look something like this:
[OperationBehavior(TransactionScopeRequired = true)]
public void Foo()
{
// Resolve the default ExceptionManager object from the container.
ExceptionManager exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();
exManager.Process(() =>
{
DAL.Foo();
return Receipt.CreateSuccessReceipt();
},
"ExceptionShielding");
}
Enterprise Library (via configuration) would then catch any exceptions and replace them with a new FaultException that is returned to the client.
[OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)]
Presumably because the transaction is now rolled back as soon as the error occurs, rather than asynchronously when the scope goes out of scope :D, this behaves like I expected things to behave originally, and I can leave my design as it is.
(I had already written up the question when trying this occured to me. Hopefully posting it Q&A style will be more helpful than not posting the question at all.)