如何存储任务的活动状态,并维护这些任务的列表的永久性

Jas*_*ger 7 c# asp.net iis session-variables task

我试图准确地了解QueueBackgroundWorkerItem线程启动的任务的状态.我可以访问Task对象并将它们添加到我的TaskModel列表中,并将该列表对象发送到我的View.

我的视图只显示一个任务状态,无论我单击QueueWorkItem链接多少次,并启动一个新任务.我想弄清楚几件事:

  • 在MVC中,如何保存我生成的任务数量的实时列表?我假设将模型发送到视图中,我会保证一些永久性.
  • 一旦我能做到这一点,我想我可以将Task对象存储在我的列表中.但是,即使在下面的这个例子中,我似乎仍然无法知道在任何给定时间任务的状态是什么(似乎我只能知道它在添加到我的列表时是什么) .

我希望有人做过类似的事情并且可以帮助解决这个问题.谢谢!-Jason

编辑:此设置的核心要求是:

  • 即使浏览器关闭,我也需要使用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);
}
Run Code Online (Sandbox Code Playgroud)

视图:

@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>
}
Run Code Online (Sandbox Code Playgroud)

编辑,解决方案:

按照Raffaeu的建议和以下妥协,我能够找到它:

  • 我们只在任何时间运行一项任务.我不需要列表
  • 我并不真正需要按需提供的状态.我只需要知道什么时候完成

我希望能够利用任务ID稍后从ID实例化任务.事实证明这涉及到超出必要的开销.

相反,我找到了该功能Task.CompletedTask(在.NET 4.6及更高版本中可用).在异步中使用的这个允许我在完成时获取任务的状态.瞧.感谢大家的建议.

最好的部分 - 无论是关闭浏览器还是停止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();
}
Run Code Online (Sandbox Code Playgroud)

Raf*_*aeu 5

我认为你在这里遗漏了一点。

当您使用 MVC 时,您处于完全“无状态”的情况,其中异步任务由不同的线程提交和执行,因此您无法对其进行控制。您必须“获得有关任务更改的通知”的唯一方法是从该任务中获取“事件”。一个事件将通知您有关“状态已更改”的信息。Task 类不会引发事件,但具有 ContinueWith 方法。正确的方法是:

  1. 创建并启动Task并将其存储在Status某处(数据库、文本文件、会话)
  2. 使用ContinueWith上传Task数据存储中 的状态
  3. 不断查询Datastore以获取Status所有排队任务的更新版本

我认为在这个线程中,他们试图实现相同的目标: How to track if an async/awaitable task is running

  • 您并未处于完全“无状态”的情况,它只是建议您遵循该架构。您可以创建有状态的组件,例如位于内存中的单例。 (2认同)