代码之家  ›  专栏  ›  技术社区  ›  Jason P Sallinger

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

  •  7
  • Jason P Sallinger  · 技术社区  · 8 年前

    我正试图准确地了解由QueueBackgroundWorkerItem线程启动的任务的状态。我可以访问任务对象并将其添加到我的TaskModels列表中,然后将该列表对象发送到我的视图中。

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

    • 在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>
    }
    

    编辑,解决方案:

    根据拉斐的建议和以下妥协,我能够找到这样的建议:

    • 我们在任何给定时间只运行一个任务。我不需要清单
    • 我真的不需要状态随需应变。我只想知道什么时候完工

    我希望能够利用任务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();
    }
    
    1 回复  |  直到 8 年前
        1
  •  5
  •   Raffaeu    8 年前

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

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

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

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

    推荐文章