Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,128 | Comments: 45,550

filter by tags archive

TPL: Composing tasks

time to read 3 min | 417 words

What happens when you want to compose two distinct async operations into a single Task?

For example, let us imagine that we want to have a method that looks like this:

public void ConnectToServer()
    var connection = ServerConnection.CreateServerConnection(); // tcp connect
    connection.HandShakeWithServer(); // application level handshake

Now, we want to make this method async, using TPL. We can do this by changing the methods to return Task, so the API we have now is:

Task<ServerConnection> CreateServerConnectionAsync();
Task HandShakeWithServerAsync(); // instance method on ServerConnection

And we can now write the code like this:

public Task ConnectToServerAsync()
   return ServerConnection.CreateServerConnectionAsymc()
                 .ContinueWith(task => task.Result.HandShakeWithServerAsync());

There is just one problem with this approach, the task that we are returning is the first task, because the second task cannot be called as a chained ContinueWith.

We are actually returning a Task<Task>, so we can use task.Result.Result to wait for the final operation, but that seems like a very awkward API.

The challenge is figuring a way to compose those two operations in a way that expose only a single task.


Ayende Rahien


Damn it!

I was sure that I had such an elegant solution, and then you come up with this beauty.


Jes&#250;s L&#243;pez

However there is a subtle problem. If CreateServerConnection fails you will end up with an unobserved exception which will cause the entire app domain to crash if you don't catch unobserved exception in your app domain.

I use the following task extensions for composing tasks and observe antecedents:

    public static Task

<tresult ObservedContinueWith <tresult(this Task task, Func <task,> continuationFunction, TaskContinuationOptions continuationOptions)


        return task.ContinueWith(t =>


            if (t.Status == TaskStatus.Faulted)


                throw t.Exception;


            return continuationFunction(t);

        }, continuationOptions);

Ayende Rahien


What are you talking about?

Exceptions inside tasks will not kill the app domain

Jes&#250;s L&#243;pez

Yes it will. Try this code and see how the console application crashes:

    static void Main(string[] args)




            var t = GetComposedTask();





            Console.WriteLine("Press enter");


        catch (Exception ex)


            Console.WriteLine("Caugth exception {0}", ex.Message);



    static Task GetComposedTask()


        return Task.Factory.StartNew(() => { throw new Exception("Some error ocurred"); })

            .ContinueWith( _ => { Console.WriteLine("Hello from task"); });

Ayende Rahien



The actual exception is very informative:

A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

Which makes total sense.

Jes&#250;s L&#243;pez

I forgot to include Console.ReadLine after Console.WriteLine. Anyway, it crashes

Omer Mor

If you'd go the Rx path, composition is trivial:

    Task CreateServerConnectionAsync()


        return (from sc in ServerConnection.CreateServerConnectionAsync().ToObservable()

                select sc.HandShakeWithServerAsync()).Single();


Instead of a Task, you can return an observable of unit (sort of void), and have more native Rx signature:


<unit CreateServerConnectionAsync()


        return from sc in ServerConnection.CreateServerConnectionAsync().ToObservable()

               select sc.HandShakeWithServerAsync().ToObservable();


If your whole API will return observables, you could also skip the .ToObservable() task conversions.

Dan Jasek

I think Omer has the best solution. I have been underwhelmed by the implementation of Task. Cold tasks are basically useless, they forgot to make an ITask... And now Jesus' exception handling issue.

RX doesn't have any of these problems, including the need to unwrap. It is just better thought out.

I hope they add some sort of iterative await for RX before they release 5.0.

Jeff Cyr


Note that you can prevent the application crash by subscribing to TaskScheduler.UnobservedTaskException:

        TaskScheduler.UnobservedTaskException += (sender, e) =>





Use a TaskCompletionSource and set up your method to return you tc.Task and then wrap your async methods neatly to call tc.TrySetException | TrySetResult when they complete..


David Hanson

I "Subscribe" ;-) to the Rx approach.

We use the approach outlined by Omar to load data from mutliple domains services in Ria and works very well.


I'm definitely missing something, but why don't you just put CreateServerConnection and HandShakeWithServer inside one task?

Comment preview

Comments have been closed on this topic.


  1. The worker pattern - about one day from now

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    26 May 2016 - The client side
  2. RavenDB 3.5 whirl wind tour (14):
    25 May 2016 - Got anything to declare, ya smuggler?
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats