Task.Delay(TimeSpan.FromDays(30))
throws ArgumentOutOfRangeException due to some implementation detail.
expected: APIs taking TimeSpan should support the full range of that type.
Not all APIs support the full range of their argument's values. For example, TimeSpan.FromSeconds(double) doesn't accept the full range of _double_ values for its input. The underlying implementation imposes additional restrictions.
In your case, do you have a scenario which is blocked by Task.Delay not supporting long timeout periods (> 25-ish days)?
In your case, do you have a scenario which is blocked by Task.Delay not supporting long timeout periods (> 25-ish days)?
yes
Could you please share details? Perhaps there is a better mechanism you can use.
Monthly periodic job as example.
var nextRunTime = ...;
var now = DateTime.UtcNow;
if (now < nextRunTime) {
await Task.Delay(nextRunTime - now);
}
Monthly periodic job as example.
I'd use a task scheduler for this purpose (cronjob, windows task scheduler) which kicks off the executable that performs this operation.
Having such long paused operations in your app / service can get into troubles if e.g. the server restarts.
Also (for me) it's kind of wasting ressources to let a task "sleep" such a long time -- the bookkeeping is still there. So delegate this to the OS's schedulers.
windows task scheduler
requires complex installer
Having such long paused operations in your app / service can get into troubles if e.g. the server restarts.
There are no problem if nextRunTime is persisted.
Then there are solutions like https://www.hangfire.io/.
Or go a simple approach with a timer (interval maybe a few hours) that checks nextRunTime and if should run, queue it to the thread-pool (that's basically what schedulers do).
Similar to what @gfoidl suggested, a workaround could be to use the Task.Delay(Int32) overload with a max total millisecond count of Int32.MaxValue, and when the task runs and nextRunTime has not been reached, issue another delay for the remaining time. It seems unlikely that the API behavior would be changed, as it would have to behave the same way as above internally anyway with more complication than the workaround and there wouldn't be much benefit.
While the API is unlikely to change to support the full range of TimeSpan, it can easily be fixed to support the same range as Timer, which it relies on internally and which supports up to uint.MaxValue-1 milliseconds, which would make the 30-day repro originally reported in this issue work. I've done so at https://github.com/dotnet/runtime/pull/43708.