Ayende @ Rahien

Hi!
My name is Ayende Rahien
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,949 | Comments: 44,548

filter by tags archive

A surprise TaskCancelledException


All of a sudden, my code started getting a lot of TaskCancelledException. It took me a while to figure out what was going on. We can imagine that the code looked like this:

var unwrap = Task.Factory.StartNew(() =>
{
    if (DateTime.Now.Month % 2 != 0)
        return null;

    return Task.Factory.StartNew(() => Console.WriteLine("Test"));
}).Unwrap();

unwrap.Wait();

The key here is that when Unwrap is getting a null task, it will throw a TaskCancelledException, which was utterly confusing to me. It make sense, because if the task is null there isn’t anything that the Unwrap method can do about it. Although I do wish it would throw something like ArgumentNullException with a better error message.

The correct way to write this code is to have:

var unwrap = Task.Factory.StartNew(() =>
{
    if (DateTime.Now.Month % 2 != 0)
    {
        var taskCompletionSource = new TaskCompletionSource<object>();
        taskCompletionSource.SetResult(null);
        return taskCompletionSource.Task;
    }

    return Task.Factory.StartNew(() => Console.WriteLine("Test"));
}).Unwrap();

unwrap.Wait();

Although I do wish that there was an easier way to create a completed task.


Comments

Remco Blok

The Async CTP has a static TaskEx.FromResult method that does exactly what you do:

public static Task FromResult(TResult result) { TaskCompletionSource source = new TaskCompletionSource(result); source.TrySetResult(result); return source.Task; }

Expect this TaskEx class to be merged with the Task class for .Net 5.

Frank Quednau

3 lines of code that can be extracted into some static property hardly counts as a difficult way to create a completed task ;)

Omer Mor

Oren, have you gotten in Rx yet (as in fully grokked it)? You seem to use tasks a lot. I myself use Rx for most of my asynchronous needs. It is usually a better concept. And regarding this case, it has Observable.Empty or Observable.Return(null) helpers which could your case, had you been using Rx.

Ayende Rahien

Omer, I would love to see some real examples of TPL vs. RX code, because I haven't really been able to figure out that. And I think that with C# 5.0, TPL is a better alternative

Omer Mor

This is from SO: http://stackoverflow.com/questions/2542764/tpl-v-s-reactive-framework In general, tasks abstract single (future) values/computations and observables abstract streams of (future) values/computations. You could treat the single value case as a special case of a single value stream, and only use Rx. However if your use case primarily deals with single values, TPL might be a better feat. Also, Rx allows for much better composition (using LINQ).

From my experience, Rx works best when replacing events.

For me - Rx was a mind enhancing experience, which changed the way I perceive many problems. I advise you to take a leap of faith here, and invest some time in this ingenious framework.

Ayende Rahien

Omer, Most of what we are doing are actually do computation of a single value. For example, take a look at the type of things we do here:

public Task<BatchResult[]> BatchAsync(ICommandData[] commandDatas) { var metadata = new RavenJObject(); AddTransactionInformation(metadata); var req = jsonRequestFactory.CreateHttpJsonRequest(this, url + "/bulk_docs", "POST", metadata, credentials, convention); var jArray = new RavenJArray(commandDatas.Select(x => x.ToJson())); var data = jArray.ToString(Formatting.None);

return Task.Factory.FromAsync(req.BeginWrite, req.EndWrite, data, null)
    .ContinueWith(writeTask => req.ReadResponseStringAsync())
    .Unwrap()
    .ContinueWith(task =>
    {
        string response;
        try
        {
            response = task.Result;
        }
        catch (WebException e)
        {
            var httpWebResponse = e.Response as HttpWebResponse;
            if (httpWebResponse == null ||
                httpWebResponse.StatusCode != HttpStatusCode.Conflict)
                throw;
            throw ThrowConcurrencyException(e);
        }
        return JsonConvert.DeserializeObject<BatchResult[]>(response, new JsonToJsonConverter());
    });

}

can you should me how this would be written, Rx style?

Omer Mor

I'll give it a shot later. I guess the basic idea would be to treat it as a stream of command batches, and project it (select) into a stream of responses. Along the way we could push the handling into a dedicated thread, or use the thread/task pool. we might also easily "batch our batches" based on count or time if that could increase our performance. we might also throttle against overloading / DoS attacks for example.

I cross-posted your example in the Rx forums, for help getting an expert opinion on this (http://social.msdn.microsoft.com/Forums/en/rx/thread/3cd72a7e-fba8-4c81-9113-36ef78e2ac54).

Ayende Rahien

Omer, None of those things are actually needed or required.

BatchAsync is being called from SaveChangesAsync, and there is usually only ever to be one of them.

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
  2. Special Offer (2):
    27 May 2015 - 29% discount for all our products
  3. RavenDB Sharding (3):
    22 May 2015 - Adding a new shard to an existing cluster, splitting the shard
  4. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  5. Interview question (2):
    30 Mar 2015 - fix the index
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats