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

原文:Running async tasks on app startup in ASP.NET Core (Part 3)

作者:Andrew Lock

译者:Lamond Lu

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

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

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

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

启动任务的例子

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

  • 检查强类型配置是否合法

  • 使用数据库或者API填充缓存

  • 运行数据库迁移

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

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

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

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

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

  2. 迁移数据库需要更多的权限

  3. 开发人员不太喜欢直接运行数据库迁移

下面我们依次说明一下。

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

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

640?wx_fmt=png

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

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

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

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


640?wx_fmt=png


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

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

迁移通常需要更多的权限

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

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


640?wx_fmt=png


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

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

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

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

  • 使用EF Core全局工具进行迁移需要安装.NET Core SDK,这在生产服务器上是不需要的。

  • 如果你想安全地更新数据库,你可能还是必须对生成的脚本进行一些编辑。 迁移后的数据库结构应与现有(运行)应用程序兼容,以避免停机。

  • 微软官方文档中暗示在应用启动时运行EF Core迁移不是一个好主意!

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

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

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

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

  • 检查强类型配置是否有效。ASP.NET Core 2.2引入了配置验证,但它只在首次访问IOptions <T>类时执行此操作。 正如我在之前文章中所描述的那样,你可能希望在应用启动时进行验证,以确保你的环境和配置有效。

  • 填充缓存。 你的应用程序可能需要来自文件系统或远程服务的数据,它只需要加载一次,但加载需要耗费相当多的资源,所以在应用程序启动之前加载此数据可减少请求延迟。

  • 预连接到数据库和/或外部服务。 以类似的方式,你可以通过连接到数据库或其他外部服务来填充数据库连接池。 这些通常是相对昂贵的操作,因此是很好的用例。

  • 预编译加载应用中所有的单例服务。我认为这个一个非常有趣的想法,通过预加载依赖注入容器中注册的单例服务,你可以减少请求的响应时间。

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

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

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

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

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

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

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

总结

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

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


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CF1140G-Double Tree【最短路,矩阵乘法,树上倍增】

正题 题目链接:https://www.luogu.com.cn/problem/CF1140G 题目大意 给出一个nnn个点的树TTT&#xff0c;然后复制一份T′TT′&#xff0c;每个TTT中的点iii向T′TT′中的点iii都有连边构成一张图。 图上所有权值各不相同&#xff0c;现在qqq次询问图上两点的最短路。 1≤n≤…

数论六之计算几何——An Easy Problem,Ancient Berland Circus,Open-air shopping malls

可检验模板正确度An Easy Problem?!Ancient Berland CircusOpen-air shopping mallsAn Easy Problem?! problem 就是大讨论 #include <cmath> #include <cstdio> #include <iostream> using namespace std; #define eps 1e-6struct vec {double x, y;ve…

CodeForces:12271261(div1)1262(div2)

文章目录前言CF1227A Math ProblemDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}CodeCF1227B BoxDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}CodeCF1227C MessyDescription\text{Des…

【NET CORE微服务一条龙应用】应用部署

简介本章主要介绍https://github.com/q315523275/FamilyBucket上微服务一条龙应用&#xff0c;在实际使用中的应用部署&#xff0c;以原始方式部署非docker部署应用主要包括&#xff1a;1、网关应用部署2、授权认证应用部署3、配置中心查询服务端应用部署4、综合管理应用部署5、…

牛客网区间dp练习

NC13230 合并回文子串 NC16129 小小粉刷匠 NC19909 [CQOI2007]涂色PAINT NC19997 [HAOI2016]字符合并 NC20238 [SCOI2003]字符串折叠 NC20252 [SCOI2007]压缩 NC20312 [SDOI2008]SUE的小球 POJ3042 Grazing on the Run

CF516D-Drazil and Morning Exercise【树上差分,倍增】

正题 题目链接:https://www.luogu.com.cn/problem/CF516D 题目大意 给出一棵nnn个点的树&#xff0c;定义f(x)f(x)f(x)表示距离点xxx最远的点的距离&#xff0c;qqq次询问给出一个kkk&#xff0c;要求一个最大的连通块满足连通块中所有点的f(x)f(x)f(x)最大最小差值不能超过k…

容斥问卷调查反馈——Co-prime,Character Encoding,Tree and Constraints,「2017 山东一轮集训 Day7」逆序对

文章目录Co-primesourcesolutioncodeCharacter EncodingsourcesolutioncodeTree and Constraintssourcesolutioncode「2017 山东一轮集训 Day7」逆序对sourcesolutioncodeCo-prime source TTT组数据&#xff0c;给出&#x1d43f;,&#x1d445;,&#x1d441;&#x1d43f;, …

手工修复Azure DevOps无法连接到Azure的问题

点击上方蓝字关注“汪宇杰博客”今天我在为一个从TFVC迁移到Git的老项目重新配置发布到Azure App Service的CI/CD管线的时候&#xff0c;Azure DevOps竟然爆了。这是一个微软已知的bug&#xff0c;目前还未修复&#xff0c;我来带大家看看如何手工workaround这个问题。首先&…

Loj#576-「LibreOJ NOI Round #2」签到游戏【线段树】

正题 题目链接:https://loj.ac/p/576 题目大意 给出一个长度为nnn的序列aaa&#xff0c;还有一个未知序列bbb&#xff0c;你每次可以花费gcd⁡ilrai\gcd_{il}^r a_igcdilr​ai​的代价得到∑ilrbi\sum_{il}^rb_i∑ilr​bi​的值。 每次修改aaa中的一个数&#xff0c;求得到b…

NC14732 锁

NC14732 锁 题意&#xff1a; n个居民&#xff0c;门上有k把锁&#xff0c;每个居民有若干钥匙&#xff0c;为1到k的一个子集&#xff0c;如果几名居民的钥匙的并集是1到k&#xff0c;即他们拥有全部锁的对应钥匙。 求最小的k&#xff0c;使得可以适当地给居民们每人若干钥匙…

CodeForces:1103(div1)1104(div2)

文章目录前言CF1104A Splitting into digitsDescription\text{Description}DescriptionSolution\text{Solution}SolutionDescription\text{Description}DescriptionCF1104B Game with stringDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text…

专题突破一之分块——Untitled Problem II,Balanced Lineup,[ioi2009]Regions

文章目录SP2940 UNTITLE1 - Untitled Problem IIsourcesolutioncodeBalanced LineupsourcecodeCount on a tree II[ioi2009]RegionsSP2940 UNTITLE1 - Untitled Problem II source solution 分块 si{sik(i−l1)sikik(1−l)l≤i≤rsik(r−l1)r<is_i\begin{cases} s_ik\tim…

.NET Core实战项目之CMS 第十七章 CMS网站系统的部署

目前我们的.NET Core实战项目之CMS系列教程基本走到尾声了&#xff0c;通过这一系列的学习你应该能够轻松应对.NET Core的日常开发了&#xff01;当然这个CMS系统的一些逻辑处理还需要优化&#xff0c;如没有引入日志组件以及缓存功能&#xff0c;权限目前只支持控制到菜单&…

ICPC2019南昌区域赛

ICPC2019南昌区域赛 题号题目知识点难度A9102BA Funny Bipartite Graph状压dp思维稳银快金CAnd and Pair二项式定理快铜DBitwise TreeEBob’s Problem思维&#xff0c;生成树签到FDynamic Suffix ArrayGEating Plan思维题稳铜快银HPowers of TwoIResistanceJSummonKTreeLWho i…

Loj#510-「LibreOJ NOI Round #1」北校门外的回忆【线段树】

正题 题目链接:https://loj.ac/p/510 题目大意 给出一个代码 function add(x,v)while x < n dos[x] s[x] xor vx x lowbit(x) //注意&#xff0c;这里是 lowbit&#xff0c;这也是两份代码唯一的区别end while end functionfunction query(x)ans 0while x > 0 doa…

如何用EFCore Lazy Loading实现Entity Split

α角 与 β角支持 现实生活 的 计算机系统&#xff0c;总有着两大偏差&#xff0c;第一个是 现实生活 与 计算机系统 的α角&#xff0c;另外一个是计算机系统的 逻辑设计 与 物理设计 的β角。举个栗子&#xff1a;α角&#xff1a;假设某个公司的商业流程&#xff0c;我们在做…

CodeForces:372(div1)div373(div2)

文章目录前言CF373A Collecting Beats is FunDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}CodeCF373B Making Sequences is FunDescription\text{Description}DescriptionSolution\text{Solution}SolutionCF372A Counting Kangaro…

一二三系列之CodeChef分块——Chef and Churu,Chef and Problems,Children Trips

文章目录Chef and ChurusourcesolutioncodeChef and ProblemssourcesolutioncodeChildren TripssourcesolutioncodeChef and Churu source solution 对于单独的iii&#xff0c;查询可以用线段树/树状数组O(nlog⁡n)O(n\log n)O(nlogn)&#xff0c;这暗示可以平衡查询修改次数…

Bob‘s Problem

Bob’s Problem 题意&#xff1a; 一个有n个点的图&#xff0c;其中边分为白色和黑色&#xff0c;每个边都有边权&#xff0c;所选白边的数量的数量不能超过k&#xff0c;问现在选择一些边&#xff0c;使得所有点连通&#xff0c;问最大权值是多少&#xff1f; 题解&#xf…

.NET Core 开源项目 Anet 在路上

今天给大家介绍我刚开源的一个 .NET Core 项目&#xff1a;Anet。Anet 的目标是实现一个 .NET Core 通用库、通用框架和通用模板。我给它的定义是&#xff1a;A .NET Core Common Lib, Framework and Boilerplate.它的取名正是来自于这句话的前面四个字母&#xff1a;ANET。Ane…