ASP.NET Web API中的并行数据刷新

我想告诉您,在对REST服务的请求期间我们如何组织后台数据更新。

任务如下:系统存储用户数据。 该服务是独立运行的,无法直接访问带有此数据的数据库。 为了使服务正常工作,有必要在其内部数据库中包含用户的名称和姓氏。 可以在请求时从当前用户的身份获取它们。 在每个请求期间添加或更新名称所必需。 最好在单独的线程中实现此目的,以使这项工作不会影响主请求的执行时间。

任务细化


在服务数据库中,我们存储用户的名称和姓氏。 客户需要他们提供有关谁创建或修改资源的信息。

此数据没有系统意义:如果突然在数据库中没有必要的记录,则不会发生任何不良情况。 因此,我们不想使用QueueBackgroundWorkItem在ASP中注册后台工作,以使应用程序域的重载复杂化。
建议尽可能简单地解决问题。

对于那些想了解有关ASP.NET中的后台任务的更多信息的人,我建议您阅读一篇不错的文章

解决方案


我们有一个DbRefresher类,它在RefreshAsync方法中添加或更改用户数据。

我们的控制器使用Authorize属性。 将我们的后代添加到此类,并重写OnAuthorization方法:

public override void OnAuthorization(HttpActionContext actionContext) { base.OnAuthorization(actionContext); if (IsAuthorized(actionContext)) DbRefresher.RefreshAsync(actionContext.RequestContext.Principal) .ContinueWith(t => { LogFactory.For<AuthorizeAndRefreshUserAttribute>() .ErrorException("Error occured", t.Exception); }, TaskContinuationOptions.OnlyOnFaulted); } 

DbRefresher.RefreshAsync是一个异步方法,该方法返回一个Task对象,该对象在另一个线程中继续执行。 OnAuthorize方法将立即退出,而无需等待任务完成。 发生崩溃时,错误消息将添加到日志中。

仅此而已:剩下的就是用新属性的名称替换控制器中的Authorize属性。 在检查了当前用户的权限后,新属性立即返回控制权,此后控制器开始工作。 该数据库将在控制器准备响应的同时进行更新。

测试中


同时运行多个服务请求的测试将有助于识别可能的问题:

 [TestMethod] public void ConcurrentTest() { const int threadCount = 10; var tasks = new Task[threadCount]; for (int i = 0; i < threadCount; i++) { // DoOperations contains several CRUD operations on resources tasks[i] = Task.Factory.StartNew(DoOperations); } Task.WaitAll(tasks); } 

问题所在


如果对于控制器的某些操作方法的操作,要求数据库显然包含当前用户的数据,则此方法不合适。 您将必须在方法主体中使用对DbRefresher.RefreshAsync的显式调用。

将新用户添加到具有多个同时请求的数据库时,可能会出现问题。 如果试图将用户添加到具有现有键的表中,则应捕获主键冲突异常并停止工作。 然后,所有有关更新用户数据的工作将仅由一个线程执行。

结论


这种方法已经在Konfermit的一项服务中成功运行了一年多。
在我看来,简单而优雅。 了解社区的意见会很有趣。

Source: https://habr.com/ru/post/zh-CN439628/


All Articles