Reputation: 59
My application currently executes Adobe Illustrator with some command. Waits when result file appears in some exact folder (with async function) and does something with file when it's ready.
But the problem is, sometimes Adobe Illustrator fails and app keeps waiting. In such cases I can't figure out, how can I apply timeout mechanism to kill Adobe Illustrator and skip current process.
Here is the code:
...
await WhenFileCreated(result_file_name);
if (File.Exists(result_file_name))
{
...
public static Task WhenFileCreated(string path)
{
if (File.Exists(path))
return Task.FromResult(true);
var tcs = new TaskCompletionSource<bool>();
FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(path));
FileSystemEventHandler createdHandler = null;
RenamedEventHandler renamedHandler = null;
createdHandler = (s, e) =>
{
if (e.Name == Path.GetFileName(path))
{
tcs.TrySetResult(true);
watcher.Created -= createdHandler;
watcher.Dispose();
}
};
renamedHandler = (s, e) =>
{
if (e.Name == Path.GetFileName(path))
{
tcs.TrySetResult(true);
watcher.Renamed -= renamedHandler;
watcher.Dispose();
}
};
watcher.Created += createdHandler;
watcher.Renamed += renamedHandler;
watcher.EnableRaisingEvents = true;
return tcs.Task;
}
How to apply timeout to this? Any suggestions?
Upvotes: 5
Views: 15886
Reputation: 120450
The simplest way would be to race a Task.Delay
against the actual task:
await Task.WhenAny(WhenFileCreated(result_file_name),
Task.Delay(TimeSpan.FromSeconds(5));
A better way would be implement cancellation in your async method
public static Task WhenFileCreated(string path,
CancellationToken ct =
default(CancellationToken))
{
//...
var tcs = new TaskCompletionSource<bool>();
ct.Register(() => tcs.TrySetCanceled())
//...
}
...and then pass in a cancellation token with a timeout:
using(var cts = new CancellationTokenSource(5000))
{
try
{
await WhenFileCreated(string path, cts.Token);
}
catch(TaskCanceledException)
{
//...
}
}
Upvotes: 10
Reputation: 1391
Try modifying your code to set this timeout for example.
var tcs = new TaskCompletionSource<TestResult>();
const int timeoutMs = 20000;
var ct = new CancellationTokenSource(timeoutMs);
ct.Token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: false);
More details you can find in: Timeout an async method implemented with TaskCompletionSource
Upvotes: 0