Async Wandering Part 9 — awaiting with timeout

This is the ninth part of the Async Wandering series. For your convenience you can find other parts in the table of contents in Part 1 – Why creating Form from WinForms in unit tests breaks async?

In previous part I mentioned multiple ways to await a task with timeout. Let’s see them.

Sketch

Let’s start with this code:

We will say that this code runs forever (even though it would finish after a day). The question is how do we call the method in line 8 with some timeout?

Let’s also add the following helper method:

It waits for a second and throws an exception, nothing big here.

WARNING: In examples below I don’t handle timeout exception properly. Don’t do it this way! Always await all your tasks or exceptions will be propagated by GC and kill your application in an out-of-band manner.

Solution 1 — timeouting manually

General trick is to wait for two tasks and throw exception when timeout happens:

Since Task.WhenAny returns task which resulted first, we need to wait for it as well.

Writing that code everywhere may be tedious. Let’s look further.

Solution 2 — extension method

That’s basically the same as before. However, this time we wrap the logic in one method and that’s probably the solution we are looking for.

Let’s explore some more.

Soltuion 3 — custom SynchronizationContext

This time we are going to use custom context and timeout over there:

That’s super similar to awaiting void which we have already seen in Part 5. Once we start executing method we fire a timeout as well. Bonus points, this works for async void methods as well. The advantage is we handle all continuations on the context so we can timeout them selectively, as needed. This is probably an overkill, though.

Solution 4 — custom task type

We can use custom task and timeout there:

Notice first line – we use async TimeoutableTask. We need to provide a builder for it which is trivial in our case. We just delegate to regular logic and also fire a timeout task in line 26.