原文:Running async tasks on app startup in ASP.NET Core (Part 3)
作者:Andrew Lock
译者:Lamond Lu

之前我写了两篇有关在ASP.NET Core中运行异步任务的博文,本篇博文是对之前两篇博文中演示示例和实现方法的简短跟进。

你可以通过以下链接查看之前的博文。

启动任务的例子

在之前博客中,我收到的最常见的反馈是关于我在描述问题时使用的例子。在我最初的博客中,我列举了3种可能场景,在这3种场景中,你希望在ASP.NET Core应用启动时运行一些异步任务。

  • 检查强类型配置是否合法
  • 使用数据库或者API填充缓存
  • 运行数据库迁移

对于前两种场景,没有任何问题,但是对于数据库迁移,一些博友提出了一些疑问。其实在两篇博文中我一直都反复说明,数据库迁移作为启动任务不是一个很好的方案,这里我只是想用它作为一个说明如何在ASP.NET Core程序启动时运行异步任务的例子。现在来看,当时使用这个例子是非常失败的。

数据库迁移是一个糟糕的选择

那么为什么在ASP.NET Core应用启动时,运行数据库迁移任务会是一个问题呢?毕竟,在应用程序开始处理请求之前,你肯定要完成数据库迁移!

其实这里其实有3个问题:

  1. 数据库迁移是应该是单线程的
  2. 迁移数据库需要更多的权限
  3. 开发人员不太喜欢直接运行数据库迁移

下面我们依次说明一下。

数据库迁移应该是单线程的

扩展一个Web应用最常用的方式之一是进行横向扩展,启动多个运行实例并使用负载均衡分发请求

这种Web集群扩展的方案是非常有效的,特别是当当前应用是无状态的(请求被分发到各个应用程序中,如果一个应用程序崩溃,其他的Web应用实例依然可以处理请求)。

但是不幸的是,如果尝试将数据库迁移作为应用启动任务,你很可能就会遇到问题。如果有超过1个以上的实例同时启动,多个数据库迁移任务将同时运行。

虽然并不能保证你一定会遇到麻烦,但除非你非常小心地确保幂等更新和错误处理,否则你很可能会陷入困境。

你肯定不希望使用这种方法,因为它可能产生的数据库完整性问题。 这里一个更好的选择是先启动单个实例完成迁移操作。 这样数据库迁移任务变成一个单线程任务,自然也就避开最严重的危险。

这种方法比将数据库迁移作为启动任务运行更有意义,但它更安全,更容易实现。

当然,这不是唯一的选择。 如果你对启动任务迁移的想法有所了解,那么你可以使用分布式锁来确保只有一个应用程序实例来运行迁移脚本。 然而,这并没有解决第二个问题......

迁移通常需要更多的权限

通常来说,最佳实践是你必须限制你的应用程序,以便他们只有权访问和修改所需的资源。 如果报表应用只需要读取销售数据,那么它应该无法修改它们,或者更改数据库表结构! 为指定的连接字符串配置可操作的权限,可以防止在的的应用出现安全问题时产生大量影响。

如果你正在使用Web应用程序本身来运行数据库迁移,那么该Web应用程序自然需要数据库权限才能执行高风险活动,例如修改数据库表结构,更改权限或更新/删除数据。 你真的希望您的Web应用程序能够删除你的学生表吗?

同样,你可以使用一些特定的实现,例如,与正常的数据库访问相比,使用不同的连接字符串进行迁移。 但是,如果使用外部迁移过程,你根本无法锁定Web应用程序进程。

开发人员不习惯直接运行EF Core迁移

这是一个不那么明显的观点,但是很多人表示在生产环境中使用EF Core迁移工具可能不是一个好主意。

就个人而言,我已经有1年多没有在生产环境中使用EF Core迁移了,到目前为止迁移工具肯定已经有所改善。 话虽如此,我仍然看到一些问题:

就我自己而言,我经常使用DbUp和FluentMigrator,而不会使用EF Core迁移。我发现它们都运行良好。

因此,如果数据库迁移任务不适合应用启动任务示例,那么哪些任务才是比较适合的呢?

比较适合作为启动任务的一些例子

虽然在之前的博文中我已经反复提到了一些例子,但我还是将在下面再次描述它们。这里其他博友还给我一些有趣的补充。

  • 检查强类型配置是否有效。ASP.NET Core 2.2引入了配置验证,但它只在首次访问IOptions 类时执行此操作。 正如我在之前文章中所描述的那样,你可能希望在应用启动时进行验证,以确保你的环境和配置有效。
  • 填充缓存。 你的应用程序可能需要来自文件系统或远程服务的数据,它只需要加载一次,但加载需要耗费相当多的资源,所以在应用程序启动之前加载此数据可减少请求延迟。
  • 预连接到数据库和/或外部服务。 以类似的方式,你可以通过连接到数据库或其他外部服务来填充数据库连接池。 这些通常是相对昂贵的操作,因此是很好的用例。
  • 预编译加载应用中所有的单例服务。我认为这个一个非常有趣的想法,通过预加载依赖注入容器中注册的单例服务,你可以减少请求的响应时间。

使用健康检查来完成启动任务

我完全同意有关数据库迁移的反馈。 当这不是一个好主意时,将它们用作启动任务的示例有点误导,特别是因为我个人不使用我所描述的方法!

然而,很多人都同意我所描述的另外一种方法 - 在启动Kestrel服务器和处理请求之前运行启动任务。

这里Damian Hickey针对这个方案提出了一个问题,他建议尽快启动Kestrel服务器。 他建议在所有启动任务完成后,使用运行健康检查向负载均衡器发出信号,表明应用程序已准备好开始接收请求。 与此同时,所有非健康检查流量(如果负载均衡器正在执行此任务,则不应该有任何流量)将收到503服务不可用。

这种方法的主要好处是它可以避免网络超时。 一般来说,应用程序最好能尽快的针对请求返回错误代码,而不是根本不响应请求,并导致客户端超时。 这减少了客户端所需的资源数量。 通过较早启动Kestrel服务器,应用程序可以更早地开始响应请求,即使响应是“未就绪”响应。

这实际上与我在第一篇文章中描述的方法非常相似,但是我没有选用它了,因为它太复杂了,而且没有达到我设定的目标。 从技术上来说,在那篇文章中,我只是关注在Kestrel服务器启动之前运行任务的方法,健康检查方法不能完成这个功能。

然而,Damian提出的问题让我再次思考。 在我下一篇博客中,我将描述如何使用ASP.NET Core 2.2的健康检查功能向负载均衡器发送信号,表明应用程序已经完成了所有启动任务。

总结

在这篇文章中,我分享了我之前关于在ASP.NET Core应用程序启动时运行异步任务的一些反馈。 这里最大的问题是我选择使用EF Core数据库迁移作为启动任务的示例。 数据库迁移不适合在应用程序启动时运行,因为它们通常需要由单个进程运行,并且需要比更多的数据库权限。

我提供了一些比较适合作为的启动任务的场景,并且描述了Damian给出的建议 - 尽快启动Kestrel服务器,并使用运行状况检查来指示任务何时完成。 我将在下一篇文章中描述如何实现这一功能。

如何在ASP.NET Core程序启动时运行异步任务(3)的更多相关文章

  1. 如何在ASP.NET Core程序启动时运行异步任务(2)

    原文:Running async tasks on app startup in ASP.NET Core (Part 2) 作者:Andrew Lock 译者:Lamond Lu 在我的上一篇博客中 ...

  2. 如何在ASP.NET Core程序启动时运行异步任务(1)

    原文:Running async tasks on app startup in ASP.NET Core (Part 1) 作者:Andrew Lock 译者:Lamond Lu 背景 当我们做项目 ...

  3. 在 ASP.NET Core 程序启动前运行你的代码

    一.前言 在进行 Web 项目开发的过程中,可能会存在一些需要经常访问的静态数据,针对这种在程序运行过程中可能几乎不会发生变化的数据,我们可以尝试在程序运行前写入到缓存中,这样在系统后续使用时就可以直 ...

  4. 探索ASP.Net Core 3.0系列四:在ASP.NET Core 3.0的应用中启动时运行异步任务

    前言:在本文中,我将介绍ASP.NET Core 3.0 WebHost的微小更改如何使使用IHostedService在应用程序启动时更轻松地运行异步任务. 翻译 :Andrew Lock   ht ...

  5. ASP.NET Core 3.x启动时运行异步任务(一)

    这是一个大的题目,需要用几篇文章来说清楚.这是第一篇.   一.前言 在我们的项目中,有时候我们需要在应用程序启动前执行一些一次性的逻辑.比方说:验证配置的正确性.填充缓存.或者运行数据库清理/迁移等 ...

  6. ASP.NET Core 3.x启动时运行异步任务(二)

    这一篇是接着前一篇在写的.如果没有看过前一篇文章,建议先去看一下前一篇,这儿是传送门   一.前言 前一篇文章,我们从应用启动时异步运行任务开始,说到了必要性,也说到了几种解决方法,及各自的优缺点.最 ...

  7. ASP.NET Core 的启动和运行机制

    目录 ASP .NET Core 的运行机制 ASP .NET Core 的启动 ASP .NET Core 的管道和中间件 参考 ASP .NET Core 的运行机制 Web Server: AS ...

  8. 如何在ASP.NET Core中使用JSON Patch

    原文: JSON Patch With ASP.NET Core 作者:.NET Core Tutorials 译文:如何在ASP.NET Core中使用JSON Patch 地址:https://w ...

  9. 如何在 asp.net core 3.x 的 startup.cs 文件中获取注入的服务

    一.前言 从 18 年开始接触 .NET Core 开始,在私底下.工作中也开始慢慢从传统的 mvc 前后端一把梭,开始转向 web api + vue,之前自己有个半成品的 asp.net core ...

随机推荐

  1. Firefox Profile (2)

    一些关于selenium copy Firefox profile to a temp directory的讨论 https://stackoverflow.com/questions/6787095 ...

  2. 开发你的第一个BLE应用程序—Blinky

    本文将和大家一起编写我们的第一个BLE应用程序:Blinky(闪灯程序),哪怕你之前没有任何BLE开发经验,也不用担心,只要跟着文中所述步骤,你就可以一步步搭建自己的第一个BLE应用程序.通过这个Bl ...

  3. log4j java项目中的配置

    第一步你需要 相关的jar包 第二歩你需要一个关于log4j的配置文件 第三歩 你需要一个检测用的java 文件 导入这两个jar包进你的项目中 commons-logging.jar log4j-1 ...

  4. 从壹开始微服务 [ DDD ] 之十一 ║ 基于源码分析,命令分发的过程(二)

    缘起 哈喽小伙伴周三好,老张又来啦,DDD领域驱动设计的第二个D也快说完了,下一个系列我也在考虑之中,是 Id4 还是 Dockers 还没有想好,甚至昨天我还想,下一步是不是可以写一个简单的Angu ...

  5. 基于Unity的AR开发初探:第一个AR应用程序

    记得2014年曾经写过一个Unity3D的游戏开发初探系列,收获了很多好评和鼓励,不过自那之后再也没有用过Unity,因为没有相关的需求让我能用到.目前公司有一个App开发的需求,想要融合一下AR到A ...

  6. ES 14 - (底层原理) Elasticsearch内部如何处理不同type的数据

    目录 1 type的作用 2 type的底层数据结构 3 探究type的存储结构 3.1 创建索引并配置映射 3.2 添加数据 3.3 查看存储结构 4 关于type的最佳实践 1 type的作用 在 ...

  7. Windows下安装tesserocr

    很难受,由于这两天重装了系统,又得重新配置环境了,而我在安装tesserocr的时候踩了一些坑,于是想写出来分享一下. 一.安装tesseract 要安装tesserocr,首先要下载tesserac ...

  8. Java进阶篇设计模式之十 ---- 访问者模式和中介者模式

    前言 在上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern).本篇则来学习下行为型模式的两个模式,访问者模式(Visito ...

  9. 初探奥尔良(Orleans)

    由于工作上关系目前经常被各种并发数据问题搞得焦头烂额,要么要性能舍弃数据上得一致性,要么要一致性但是却得到了特别糟糕的响应.难道鱼和熊掌真的无法兼得吗? 然后找到了类似奥尔良这种基于Actor模型的k ...

  10. List-LinkedList、set集合基础增强底层源码分析

    List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...