WriteAsync with timeout
Asked Answered
M

1

2

I try to code a simple async write with timeout as below and expect the function to throw a TaskCanceledException given a very large buffer and small waitTime. However, this does not happen. WriteAsync will block for many seconds until the write completes. What am I missing?

public async void WriteWithTimeout(Stream os, byte[] buf, int waitMs)
{
    CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds.
    await os.WriteAsync(buf, 0, buf.Length, tokenSource.Token);

    return;
}

Call from GUI thread:

try
{
    WriteWithTimeout(response.OutputStream, buf100M, w1ms);
}
catch(OperationCanceledException e)
{
    ConsoleWriteLine("Failed with exception: {0}", e.Message);
}        
Meza answered 13/12, 2017 at 1:23 Comment(2)
shouldn't you do tokenSource.CancelAfter(TimeSpan.FromMilliseconds(waitMs)); AFTER WriteAsync and then await it? e.g. this answer here: #23477076Hohenlohe
Am I crazy or this is all I need to do: Task task = response.OutputStream.WriteAsync(buf, 0, buf.Length); if(task.Wait(maxWait)) { // OK. } else { // timed out. }Meza
L
10

You can't catch a async void. It must return a task and you have to await it.

public async Task WriteWithTimeout(Stream os, byte[] buf, int waitMs)
{
    CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds.
    await os.WriteAsync(buf, 0, buf.Length, tokenSource.Token);

    return;
}

gui code

try
{
    await WriteWithTimeout(response.OutputStream, buf100M, w1ms);
}
catch(OperationCanceledException e)
{
    ConsoleWriteLine("Failed with exception: {0}", e.Message);
}

The cancellations still happen but you just don't observe them.

Update:

It is possible that os.WriteAsync( is just a synchronous completion just backed by a Task.Run( behind the scenes1. The cancellation token won't cancel a already running Task.Run(. In that case the best way is to wrap the cancellation up in a Task.WhenAny( and pass in the token to there too via a infinitely long Task.Delay(.

public async Task WriteWithTimeout(Stream os, byte[] buf, int waitMs)
{
    CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds.
    var task = os.WriteAsync(buf, 0, buf.Length, tokenSource.Token);
    var waitedTask = await Task.WhenAny(task, Task.Delay(-1, token));
    await waitedTask; //Wait on the returned task to observe any exceptions.
}

1. For example that is the default behavior of a FileStream if you don't pass inFileOptions.Asynchronous to the constructor

Loreeloreen answered 13/12, 2017 at 1:31 Comment(6)
Waiting on the async Task works. Thank you. I need to provide a library to some casual users and do not want to bother them with async-await. So I try to wrap the WriteWithTimeout in another function as follow: try { Task task = WriteWithTimeout(response.OutputStream, buf100M, w1ms); }Meza
(continue from above. Sorry, I have problem with formatting the message.) task.Wait(); } catch(Exception e) { } And again, the cancellation is ignored and WriteAsync blocks until the write op completes.Meza
You can't call task.Wait() on a UI thread and have the UI be responsive. That is just the way it works. If you don't want your UI to lock up you need to use await or run the code explicitly in a background thread using a Task.Run( in the GUI code that calls it then using a this.BeginInvoke( to get back to the UI when the work is done from inside the Task.Run(Loreeloreen
I actually want the UI to block, but only for the given Waitms milliseconds. The problem is the cancellation no longer takes affect, and the UI is blocked until the write op complete. In other words, cancellation works when the UI function is declared with asysn and calls await on WriteWithTimeout, but cancellation is ignored when UI function is not declared with async and uses task.Wait to invoke WriteWithTimeOut.Meza
@ChuBun So is the above answer by Scott working for you? Are you able to start ReadAsync or WaitAsync and see them timeout? Could you provide some update on this as I am running into same issue?Wateriness
@ChuBun ... could you also provide solution for both ReadAsync and WriteAsync? ThanksWateriness

© 2022 - 2024 — McMap. All rights reserved.