如何存储任务的活动状态,并保持这些任务列表的永久性
How to store the active status of a Task, and maintain permanency of a List of these Tasks
我正在尝试准确了解由 QueueBackgroundWorkerItem 线程启动的任务的状态。我可以访问任务对象并将它们添加到我的任务模型列表中,然后将该列表对象发送到我的视图中。
无论我单击 QueueWorkItem link 多少次并开始新任务,我的视图只显示一个任务状态。我想弄清楚几件事:
- 在 MVC 中,我如何保持生成了多少任务的实时列表?我假设通过将模型发送到视图我可以确保一些永久性。
- 一旦我可以做到这一点,我假设我将能够将任务对象存储在我的列表中。然而,即使在下面的这个例子中,我似乎仍然无法在任何给定时间知道任务的状态(似乎我只能在将它添加到我的列表时知道它是什么) .
我希望有人做过类似的事情并且可以提供帮助。
谢谢!
-杰森
编辑:此设置的核心要求是:
- 即使浏览器关闭,我也需要使用 QueueBackgroundWorkerItem 运行 一项长时间的工作
- 我选择嵌入一个任务,这样我就可以了解每项工作的持续状态 运行。我知道对于 QBWI,运行 完成一项任务会有点矫枉过正。但是我找不到其他方法可以随时知道QBWI的状态。
控制器:
List<TaskModel> taskModelList = new List<TaskModel>();
public ActionResult QueueWorkItem()
{
Task task;
ViewBag.Message = "State: ";
String printPath = @"C:\Work\QueueBackgroundWorkerItemPractice\QueueBackgroundWorkerItemPractice\WorkerPrintFile" + DateTime.Now.ToLongTimeString().ToString().Replace(":", "_") + ".txt";
System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
task = Task.Run(() =>
{
string filePath = printPath;
string text = "File line ";
if (!System.IO.File.Exists(filePath))
{
using (var stream = System.IO.File.Create(filePath)) { }
}
TextWriter tw = new StreamWriter(printPath);
for (int i = 0; i < 400; i++)
{
text = "Line " + i;
tw.WriteLine(text);
Thread.Sleep(200);
}
tw.Close();
});
var c = task.ContinueWith((antecedent) =>
{
taskModelList.Add(new TaskModel(task));
});
});
return View(taskModelList);
}
查看:
@model List<QueueBackgroundWorkerItemPractice.Models.TaskModel>
@{
ViewBag.Title = "Queue Background Worker";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message<span id="modelClass"></span></h3>
<p>Use this area to provide additional information.</p>
@{
<ul>
@foreach (var taskModel in Model)
{
<li>@taskModel.Status</li>
}
</ul>
}
编辑,解决方案:
根据 Raffaeu 的建议和以下妥协,我找到了它:
- 我们在任何给定时间都只运行完成一项任务。我不需要列表
- 我真的不需要点播状态。我只需要知道什么时候完成
我希望能够利用任务 ID 稍后从 ID 实例化任务。事实证明,这涉及比必要更多的开销。
相反,我找到了 Task.CompletedTask
功能(在 .NET 4.6 及更高版本中可用)。这在异步中使用,使我能够在任务完成时获得任务的状态。瞧。感谢大家的建议。
最棒的部分 - 这个耗时 运行ning 的任务将在我关闭浏览器...或停止 IIS 时完成。奇迹般的。
public ActionResult QueueWorkItem()
{
System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
task = Task.Run(async () =>
{
String printPath = @"C:...";
string filePath = printPath;
string text = "File line ";
if (!System.IO.File.Exists(filePath))
{
using (var stream = System.IO.File.Create(filePath)) { }
}
TextWriter tw = new StreamWriter(printPath);
for (int i = 0; i < 400; i++)
{
text = "Line " + i;
tw.WriteLine(text);
Thread.Sleep(200);
}
tw.Close();
await Task.CompletedTask;
});
var c = task.ContinueWith((antecedent) =>
{
taskID = task.Id;
status = task.Status.ToString();
try
{
string connString = WebConfigurationManager.ConnectionStrings["TaskContext"].ToString();
sqlCommand.CommandText = "INSERT INTO dbo.TaskTable (TaskId, Status) VALUES (" + taskID + ", '" + status + "')";
conn.ConnectionString = connString;
sqlCommand.Connection = conn;
conn.Open();
sqlCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
String info = ex.Message + ex.ToString() + ex.StackTrace;
throw new Exception("SQL Issue" + info);
}
finally
{
if (conn != null)
{
conn.Close();
conn = null;
}
sqlCommand = null;
}
});
});
return View();
}
我认为你在这里漏掉了一点。
当您使用 MVC 时,您处于完全 "stateless" 的情况,其中异步任务由不同的线程提交和执行,因此您失去了对它的控制。您必须 "get notified" 关于任务更改的唯一方法是从该任务中获取 "event"。一个事件将通知您 "Status Changed"。 Task class 不引发事件,但具有 ContinueWith 方法。正确的方法是:
- 创建并启动
Task
并将其 Status
存储在某处(数据库、文本文件、会话)
- 使用
ContinueWith
上传数据存储中 Task
的状态
- 持续查询
Datastore
以获取所有排队任务 Status
的更新版本
我认为在这个帖子中他们试图达到相同的目的:
How to track if an async/awaitable task is running
我正在尝试准确了解由 QueueBackgroundWorkerItem 线程启动的任务的状态。我可以访问任务对象并将它们添加到我的任务模型列表中,然后将该列表对象发送到我的视图中。
无论我单击 QueueWorkItem link 多少次并开始新任务,我的视图只显示一个任务状态。我想弄清楚几件事:
- 在 MVC 中,我如何保持生成了多少任务的实时列表?我假设通过将模型发送到视图我可以确保一些永久性。
- 一旦我可以做到这一点,我假设我将能够将任务对象存储在我的列表中。然而,即使在下面的这个例子中,我似乎仍然无法在任何给定时间知道任务的状态(似乎我只能在将它添加到我的列表时知道它是什么) .
我希望有人做过类似的事情并且可以提供帮助。 谢谢! -杰森
编辑:此设置的核心要求是:
- 即使浏览器关闭,我也需要使用 QueueBackgroundWorkerItem 运行 一项长时间的工作
- 我选择嵌入一个任务,这样我就可以了解每项工作的持续状态 运行。我知道对于 QBWI,运行 完成一项任务会有点矫枉过正。但是我找不到其他方法可以随时知道QBWI的状态。
控制器:
List<TaskModel> taskModelList = new List<TaskModel>();
public ActionResult QueueWorkItem()
{
Task task;
ViewBag.Message = "State: ";
String printPath = @"C:\Work\QueueBackgroundWorkerItemPractice\QueueBackgroundWorkerItemPractice\WorkerPrintFile" + DateTime.Now.ToLongTimeString().ToString().Replace(":", "_") + ".txt";
System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
task = Task.Run(() =>
{
string filePath = printPath;
string text = "File line ";
if (!System.IO.File.Exists(filePath))
{
using (var stream = System.IO.File.Create(filePath)) { }
}
TextWriter tw = new StreamWriter(printPath);
for (int i = 0; i < 400; i++)
{
text = "Line " + i;
tw.WriteLine(text);
Thread.Sleep(200);
}
tw.Close();
});
var c = task.ContinueWith((antecedent) =>
{
taskModelList.Add(new TaskModel(task));
});
});
return View(taskModelList);
}
查看:
@model List<QueueBackgroundWorkerItemPractice.Models.TaskModel>
@{
ViewBag.Title = "Queue Background Worker";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message<span id="modelClass"></span></h3>
<p>Use this area to provide additional information.</p>
@{
<ul>
@foreach (var taskModel in Model)
{
<li>@taskModel.Status</li>
}
</ul>
}
编辑,解决方案:
根据 Raffaeu 的建议和以下妥协,我找到了它:
- 我们在任何给定时间都只运行完成一项任务。我不需要列表
- 我真的不需要点播状态。我只需要知道什么时候完成
我希望能够利用任务 ID 稍后从 ID 实例化任务。事实证明,这涉及比必要更多的开销。
相反,我找到了 Task.CompletedTask
功能(在 .NET 4.6 及更高版本中可用)。这在异步中使用,使我能够在任务完成时获得任务的状态。瞧。感谢大家的建议。
最棒的部分 - 这个耗时 运行ning 的任务将在我关闭浏览器...或停止 IIS 时完成。奇迹般的。
public ActionResult QueueWorkItem()
{
System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
task = Task.Run(async () =>
{
String printPath = @"C:...";
string filePath = printPath;
string text = "File line ";
if (!System.IO.File.Exists(filePath))
{
using (var stream = System.IO.File.Create(filePath)) { }
}
TextWriter tw = new StreamWriter(printPath);
for (int i = 0; i < 400; i++)
{
text = "Line " + i;
tw.WriteLine(text);
Thread.Sleep(200);
}
tw.Close();
await Task.CompletedTask;
});
var c = task.ContinueWith((antecedent) =>
{
taskID = task.Id;
status = task.Status.ToString();
try
{
string connString = WebConfigurationManager.ConnectionStrings["TaskContext"].ToString();
sqlCommand.CommandText = "INSERT INTO dbo.TaskTable (TaskId, Status) VALUES (" + taskID + ", '" + status + "')";
conn.ConnectionString = connString;
sqlCommand.Connection = conn;
conn.Open();
sqlCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
String info = ex.Message + ex.ToString() + ex.StackTrace;
throw new Exception("SQL Issue" + info);
}
finally
{
if (conn != null)
{
conn.Close();
conn = null;
}
sqlCommand = null;
}
});
});
return View();
}
我认为你在这里漏掉了一点。
当您使用 MVC 时,您处于完全 "stateless" 的情况,其中异步任务由不同的线程提交和执行,因此您失去了对它的控制。您必须 "get notified" 关于任务更改的唯一方法是从该任务中获取 "event"。一个事件将通知您 "Status Changed"。 Task class 不引发事件,但具有 ContinueWith 方法。正确的方法是:
- 创建并启动
Task
并将其Status
存储在某处(数据库、文本文件、会话) - 使用
ContinueWith
上传数据存储中Task
的状态 - 持续查询
Datastore
以获取所有排队任务Status
的更新版本
我认为在这个帖子中他们试图达到相同的目的: How to track if an async/awaitable task is running