I have an async operation depending on another server, which takes a mostly random amount of time to complete. While the asynchronous operation is in progress, processing also takes place in the "main thread", which also takes an arbitrary amount of time to complete.
The main thread starts the asynchronous task, executes its main task, and checks the result of the asynchronous task at the end.
An asynchronous stream pulls data and calculates fields that are not critical to terminating the main stream. However, this data would be good to have (and should be included) if the calculation could be completed without slowing down the main thread.
I would like to configure the async task to run for at least 2 seconds, but so that all the time is available between the beginning and end of the main task. This is a "lazy timeout" in that it only timeouts if 2 second runtimes are exceeded and the result is actually queried. (Asynchronous task should take more than 2 seconds or the total duration of the main task)
EDIT (trying to clarify the requirements): If the async task was able to run within 2 seconds, it should not block the main thread. The main thread must allow the asynchronous task to run for at least 2 seconds. In addition, if the main thread takes more than 2 seconds, the async task should run until the main thread.
I developed a shell that works, however I would prefer a solution that is actually of type Task. See my shell solution below.
public class LazyTimeoutTaskWrapper<tResult> { private int _timeout; private DateTime _startTime; private Task<tResult> _task; private IEnumerable<Action> _timeoutActions; public LazyTimeoutTaskWrapper(Task<tResult> theTask, int timeoutInMillis, System.DateTime whenStarted, IEnumerable<Action> onTimeouts) { this._task = theTask; this._timeout = timeoutInMillis; this._startTime = whenStarted; this._timeoutActions = onTimeouts; } private void onTimeout() { foreach (var timeoutAction in _timeoutActions) { timeoutAction(); } } public tResult Result { get { var dif = this._timeout - (int)System.DateTime.Now.Subtract(this._startTime).TotalMilliseconds; if (_task.IsCompleted || (dif > 0 && _task.Wait(dif))) { return _task.Result; } else { onTimeout(); throw new TimeoutException("Timeout Waiting For Task To Complete"); } } } public LazyTimeoutTaskWrapper<tNewResult> ContinueWith<tNewResult>(Func<Task<tResult>, tNewResult> continuation, params Action[] onTimeouts) { var result = new LazyTimeoutTaskWrapper<tNewResult>(this._task.ContinueWith(continuation), this._timeout, this._startTime, this._timeoutActions.Concat(onTimeouts)); result._startTime = this._startTime; return result; } }
Does anyone have a better solution than this shell?