[英]How to handle exceptions from asynchronous methods within a SelectMany statement
[英]How to handle exceptions in methods running asynchronous?
我正在構建一個跟蹤目錄的程序,並在目錄中創建新文件時將條目添加到mysql數據庫中。 不久前,我提出了一個問題 ,即如何讓FileSystemWatcher類獨立運行,同時填充要處理的操作的背景隊列,同時FileSystemWatcher繼續搜索。 我為此找到了解決方案,但想提出一個后續問題。 首先,下面是代碼:
這是觀察者的構造函數
FileSystemWatcher watcher = new FileSystemWatcher
{
Path = directoryToWatch,
IncludeSubdirectories = true,
NotifyFilter = NotifyFilters.Attributes |
NotifyFilters.DirectoryName |
NotifyFilters.FileName,
EnableRaisingEvents = true,
Filter = "*.*"
};
watcher.Created += (OnDirectoryChange);
這是OnDirectoryChange方法:
public void OnDirectoryChange(object sender, FileSystemEventArgs e)
{
try
{
bq.QueueTask(() => storage.Insert(Settings.Default.added_files, e.Name));
}
catch (StorageException se)
{
Console.WriteLine(se.Message);
HandleException(se, se.Filename, se.Number);
}
catch (Exception ex)
{
Console.WriteLine("Catch all exceptions");
}
}
HandleException方法:
public void HandleException(Exception exceptionToHandle, string fileName = "empty", int number = 0)
{
try
{
if (number < Acceptedammountofexceptions)
{
AddExceptionToStack(exceptionToHandle, fileName);
RetryFailedFiles(new KeyValuePair<string, int>(fileName, number));
}
else if (number >= Acceptedammountofexceptions)
{
AddExceptionToCriticalList(exceptionToHandle, fileName);
Console.WriteLine("Sorry, couldnt insert this file. See the log for more information.");
}
}
catch (Exception e)
{
Console.WriteLine("Exception in HandleException");
throw;
}
}
RetryFailedFiles方法:
public void RetryFailedFiles(KeyValuePair<string, int> file)
{
int count = file.Value + 1;
try
{
bq.QueueTask(() => storage.Insert(Settings.Default.added_files, file.Key));
}
catch (StorageException se)
{
HandleException(se, file.Key, count);
Console.WriteLine(se);
}
}
如您所見,我想嘗試嘗試插入失敗的文件。 但是,目前不會重試失敗的文件。 老實說,我在自己的程序中有些失落。 如果有幫助,這里是insert語句的代碼。
public Task Insert(string tablename, string filename, int number=0)
{
try
{
string query = "INSERT INTO " + tablename + " (FILE_NAME, " +
"Id) VALUES('" + filename + "', '" + Id + "')";
using (MySqlConnection insertConn = new MySqlConnection(connectionString))
{
insertConn.Open();
if (insertConn.State == ConnectionState.Open)
{
MySqlCommand insertCmd = new MySqlCommand(query, insertConn) {CommandType = CommandType.Text};
while (insertCmd.Connection.State != ConnectionState.Open)
{
// Spinlock
}
insertCmd.ExecuteNonQuery();
insertConn.Close();
return Task.CompletedTask;
}
StorageException se = new StorageException("Couldn't connect to database!", filename, number);
Console.WriteLine(se.Message);
return Task.FromException(se);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
if (ex.Message.ToLower().Contains("duplicate"))
{
MessageBox.Show("Already exists", "Duplicate entry", MessageBoxButton.OK);
return Task.CompletedTask;
}
else
{
StorageException se = new StorageException(ex.Message, filename, number);
Console.WriteLine("Well");
return Task.FromException(se);
}
}
}
如您所見,我已經在嘗試獲取一個異常,但是,如果這有意義的話,我似乎無法對其進行跟蹤。
那么我將如何處理拋出的異常,以確保文件名在第一次失敗時會再次嘗試?
編輯:Backgroundqueue類:
public class BackgroundQueue
{
private Task previousTask = Task.FromResult(true);
private object key = new object();
public Task QueueTask(Action action)
{
lock (key)
{
previousTask = previousTask.ContinueWith(t => action()
, CancellationToken.None
, TaskContinuationOptions.None
, TaskScheduler.Default);
return previousTask;
}
}
public Task<T> QueueTask<T>(Func<T> work)
{
lock (key)
{
var task = previousTask.ContinueWith(t => work()
, CancellationToken.None
, TaskContinuationOptions.None
, TaskScheduler.Default);
previousTask = task;
return task;
}
}
}
目前尚不清楚bq
是什么,但我猜測它實際上是Queue<Func<Task>>
的包裝器-即, 被調用時啟動異步操作的事物隊列。 如果是這種情況,那么您的工作循環應該(如果打算保留順序)執行以下操作:
async Task RunQueue() {
while(keepGoing) {
if(no work) await work; // somehow, not shown; needs to be thread-safe
Func<Task> nextAction = queue.ThreadSafeDequeue();
try {
await nextAction();
} catch(Exception ex) {
DoSomethingUseful(ex);
}
}
}
重要的是await
等待異步完成,並重新引發觀察到的異常。
但是,請注意, 您的具體情況下 , Insert
正在做的工作是不是真正異步-它總是會完成(或失敗)同步。 這不一定是問題,但是:這樣的數據訪問是異步的主要候選對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.