How to cancel stream CopyToAsync when no bytes are written for longer than given time period

Viewed 529

I'd like to detect that Stream.CopyToAsync operation stalls and detect that when for longer than 1 minute no bytes are copied.

How that could be done?

2 Answers

You need to periodically check the Stream.Length, If the there is no progress, cancel the using CancellationTokenSource. Here is the code which basically uses the timer to periodically check if there is any progress with copying.

using System.IO;
using System.Threading;
using System.Threading.Tasks;
var copyingCompleted = false;
var copyBufferSize = 4096;
var interval = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;
var initialTimeoutMilliseconds = -1;//inifinite
var timer = new Timer(OnTimerElapsed,null,initialTimeoutMilliseconds,interval);
var cts = new CancellationTokenSource();
long streamLength = 0;

Stream srcStream = null;//should be your sourceStream
Stream dstStream = null;//should be your destination stream
await Copy(srcStream,dstStream,cts.Token);

public async Task Copy(Stream src,Stream dst, CancellationToken cancellationToken){
    timer.Change(interval,interval);
    try{
        await src.CopyToAsync(dst,copyBufferSize, cancellationToken);
    }
    finally{
        copyingCompleted = true;
    }
}

public void OnTimerElapsed(object state){
    if(copyingCompleted){
        //stop the timer
        timer.Change(-1,-1);
        return;
    }

    //check if the copying has progressed since the last interval callback was invoked
    if(dstStream.Length > streamLength){
        //copy has progressed, I will check you in the next interval
        streamLength = dstStream.Length;
        return;
    }

    //you didn't make any progress, I am cancelling the copy process
    cts.Cancel();
}

This is not the complete implementation, you need to take care of disposing the disposable resources, including Timer, CancellationTokenSource and Streams

Related