在 ASP.NET Core 上实现“Fire and Forget”方法的安全方法

2024-03-24

我正在尝试实现一个简单的日志记录库,该库将在多个项目中使用。库的工作是将 HTTP 请求发送到 ElasticSearch。这个库的要点是它不能等待响应。另外,我不关心任何错误/异常。它必须将请求发送到 ElasticSearch,并立即返回。我不想制作带有返回类型的接口Task,我希望他们留下来void.

下面是我的示例代码。这是“Fire and Forget”的正确且安全的实施吗?如果我用的话可以吗Task.Run()在高负载库中?或者我应该避免使用Task.Run()就我而言?另外,如果我不使用await with Task.Run(),我会阻塞线程吗? 这段代码在库中:

public enum LogLevel
{
    Trace = 1,
    Debug = 2,
    Info = 3,
    Warn = 4,
    Error = 5,
    Fatal = 6
}

public interface ILogger
{
    void Info(string action, string message);
}

public class Logger : ILogger
{
    private static readonly HttpClient _httpClient = new HttpClient(new HttpClientHandler { Proxy = null, UseProxy = false });
    private static IConfigurationRoot _configuration;

    public Logger(IConfigurationRoot configuration)
    {
        _configuration = configuration;
    }

    public void Info(string action, string message)
    {
        Task.Run(() => Post(action, message, LogLevel.Info));
        /*Post(action, message, LogLevel.Info);*/ // Or should I just use it like this?
    }

    private async Task Post(string action, string message, LogLevel logLevel)
    {
        // Here I have some logic

        var jsonData = JsonConvert.SerializeObject(log);
        var content = new StringContent(jsonData, Encoding.UTF8, "application/json");

        var response = await _httpClient.PostAsync(_configuration.GetValue<string>("ElasticLogger:Url"), content);
        // No work here, the end of the method
    }
}

这是我在 Web api 的 Startup 类中的 ConfigureServices 方法中注册记录器的方法:

public void ConfigureServices(IServiceCollection services)
{
     // ......

     services.AddSingleton<ILogger, Logger>();

     // .....
}

此代码位于我的 Web api 内的方法中:

public void ExecuteOperation(ExecOperationRequest request)
{
    // Here some business logic

    _logger.Info("ExecuteOperation", "START"); // Log

   // Here also some business logic

    _logger.Info("ExecuteOperation", "END"); // Log
}

回复:对异步方法的意外调用与 Task.Run()

由于只有少量 CPU 密集型工作Post(即创建 json 有效负载),另一个没有任何好处Task.Run- 在我看来,在线程池上调度新任务的开销将超过任何好处。 IE。

Post(action, message, LogLevel.Info);*/ // Or should I just use it like this?

是两种方法中较好的一种。您可能希望抑制与未等待的任务相关的编译器警告,并为下一个遇到代码的开发人员留下评论。

但根据斯蒂芬·克利里的明确回答,开火后忘记ASP.Net 几乎从来都不是一个好主意 https://stackoverflow.com/q/36335345。最好是卸载工作,例如通过队列、Windows 服务、Azure Web 作业等。

还有额外的危险 - 如果未等待的任务抛出,你会想要观察异常 https://stackoverflow.com/q/3284137/314291.

另请注意,此后完成的任何工作Post(例如,如果您与response)这仍然是一个需要在线程池上安排的延续任务 - 如果您触发大量线程Post方法,当它们完成时你会遇到很多线程争用。

Re : 另外,如果我不将await 与Task.Run() 一起使用,我会阻塞线程吗?

await 不需要线程 https://blog.stephencleary.com/2013/11/there-is-no-thread.html. await是要求编译器异步重写代码的语法糖。Task.Run()将在线程池上安排第二个任务,该任务在到达线程池之前只会执行少量工作PostAsync方法,这就是为什么建议不使用它的原因。

来自未等待的调用的调用者线程使用量/阻塞量Info to Post取决于之前完成了什么样的工作Task被返回。 在您的情况下,Json 序列化工作将在调用者的线程上完成(我已标记为#1),但是与 HTTP 调用持续时间相比,执行时间应该可以忽略不计。所以虽然方法没有等待Info,HTTP 调用之后的任何代码仍然需要在 Http 调用完成时进行调度,并将调度到任何可用线程上 (#2)。

public void Info(string action, string message)
{
#pragma warning disable 4014 // Deliberate fire and forget
    Post(action, message, LogLevel.Info); // Unawaited Task, thread #1
#pragma warning restore 4014
}

private async Task Post(string action, string message, LogLevel logLevel)
{
    var jsonData = JsonConvert.SerializeObject(log); // #1
    var content = new StringContent(jsonData, Encoding.UTF8, "application/json"); // #1

    var response = await httpClient.PostAsync(...), content);

    // Work here will be scheduled on any available Thread, after PostAsync completes #2
}

回复:异常处理

try..catch块与异步代码一起使用 -await will 检查是否有故障Task https://stackoverflow.com/q/5383310/314291并引发异常:

 public async Task Post()
 {
     try
     {
         // ... other serialization code here ...
         await HttpPostAsync();
     }
     catch (Exception ex)
     {
         // Do you have a logger of last resort?
         Trace.WriteLine(ex.Message);
     }
 }

尽管上述内容符合观察异常的标准,但注册一个例外仍然是一个好主意UnobservedTaskException全局级别的处理程序。

这将帮助您检测并识别未能观察到异常的位置:

TaskScheduler.UnobservedTaskException += (sender, eventArgs) =>
{
    eventArgs.SetObserved();
    ((AggregateException)eventArgs.Exception).Handle(ex =>
    {
        // Arriving here is BAD - means we've forgotten an exception handler around await
        // Or haven't checked for `.IsFaulted` on `.ContinueWith`
        Trace.WriteLine($"Unobserved Exception {ex.Message}");
        return true;
    });
};

请注意,上述处理程序仅在任务被 GC 收集时才会触发,这可能是在异常发生后的一段时间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 ASP.NET Core 上实现“Fire and Forget”方法的安全方法 的相关文章

  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • C#中如何移动PictureBox?

    我已经使用此代码来移动图片框pictureBox MouseMove event pictureBox Location new System Drawing Point e Location 但是当我尝试执行时 图片框闪烁并且无法识别确切
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • 使用 x509 证书签署 json 文档或字符串

    如何使用 x509 证书签署 json 文档或字符串 public static void fund string filePath C Users VIKAS Desktop Data xml Read the file XmlDocum
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new

随机推荐

  • 为什么SSIS创建这个任务失败?

    我编写了以下代码来实现通过 HTTP 获取文件的 SSIS 控制流任务 using System using Microsoft SqlServer Dts Runtime namespace HttpTask DtsTask Displa
  • 防止 ASP.NET Core 中拒绝服务 (DoS) 攻击的最佳实践

    我正在寻找有关 ASP NET Core Web 应用程序的拒绝服务 DoS 保护 缓解的最佳实践建议 指南 可能来自 Microsoft 到目前为止我发现的主要两个选项是 AspNetCore速率限制 https github com s
  • == 与 .NET 中的 Object.Equals(object)

    因此 当我还是个新手时 与现在的新手相比 我曾经认为这两个东西是彼此的语法糖 即使用一个而不是另一个只是个人喜好 随着时间的推移 我发现这两者不是一回事 即使在默认实现中也是如此 请参阅this http web archive org w
  • 是什么让Python3的打印函数线程安全?

    我在各种邮件列表和论坛上看到人们不断提到 Python 3 中的打印函数是线程安全的 根据我自己的测试 我认为没有理由怀疑这一点 import threading import time import random def worker l
  • 从引用创建shared_ptr

    我对 C 比较陌生 这似乎是一个菜鸟问题 但我无法使用互联网上的其他资源来解决它 我正在尝试从引用创建一个shared ptr 我有以下内容Book class include
  • 将“正常”std::string 转换为 utf-8

    让我们看看我是否可以在没有太多事实错误的情况下解释这一点 我正在编写一个字符串类 我希望它使用utf 8 存储在 std string 中 因为它是内部存储 我希望它能够同时 正常 std string and std wstring作为输
  • 如何仅删除一些方面标签?

    Using facet wrap 是否可以只删除一些方面标签 在下面的示例中 我希望物种标签仅出现在每行的第一列中 我知道我可以使用labeller功能 但不包括如何更改单个标签 data iris library tidyr librar
  • 在 firebase 中看不到请求标头的值?

    我执行以下操作 var headers new Headers headers append bunny test headers append rabbit jump fetch blahurl com someservice heade
  • 为什么 svcutil.exe 的 /reference 选项不起作用?

    我正在尝试使用 svcutil exe 从一组 wsdl 文件中仅生成服务契约 接口 当我这样做时 从 http 托管的 wsdl 它会获取包含的模式并为它们生成所有代码 Great 我会做什么REALLY然而 我喜欢做的是使用一组已经使用
  • SVG 线条动画不起作用

    I am trying to create an effect where smoke comes out of a vessel Like this example where smoke comes out of a coffee cu
  • 删除记录前检查规则违规情况

    我想为我的 SQL Server 2005 数据库中的许多实体实施 软删除 方案 我的意思是 如果没有违反引用完整性规则 我想从表中删除一行 否则我将在记录上设置一个标志以表示它已被删除 我希望强制执行此 软删除 模式的表必须将 无操作 应
  • 如何将两个小部件放置在同一行中?

    我有国家 地区代码 DropdownMenu 和电话 TextFormField 如何将它们放在同一级别 我尝试过对齐小部件 Row children
  • 更改 Android numberpicker 分隔线颜色

    我想将上面显示的数字选择器的分隔线颜色 蓝色 更改为透明 我尝试了很多事情 比如 number picker setDividerDrawable getResources getDrawable R color transparent n
  • “可选类型‘字符串’的值?”没有打开;您是想使用“!”吗?或者 '?' ?”

    我研究 iOS 或 Swift 的时间并不长 通过最新的 Xcode 更新之一 我在计算机上制作的许多应用程序现在似乎都在使用过时的语法 Xcode 告诉我们将其转换为新语法 但通常这并不能解决任何问题 而且我遇到了一个新问题 这是我在语法
  • CloudKit推送通知,应用程序在后台运行

    iOS8 2 app在后台运行时 不会收到任何推送通知 而如果它在前台运行 它可以很好地接收推送通知 知道发生了什么事吗 运行于CloudKit Development模式 订阅用于添加 编辑和删除 并使用以下内容didReceiveRem
  • DynamoDB ProjectionExpression 排除属性(除一个字段外的所有字段)

    我有一个要求 我的 dynamodb 表具有许多属性 并且我需要投影表达式中的所有属性 除了我不需要响应的一两列 我正在扫描桌子 有没有一种方法可以在 ProjectionExpression 中定义它 除了这一列 我见过一些示例 其中 P
  • 左外连接不返回主表中的所有记录

    当我执行左外连接时 我希望在添加连接表之前获取查询将返回的所有记录 但它仅返回与连接表匹配的记录 即 表中不存在 092387 的记录 文档 所以我只想为该记录的 文件名 字段返回 null 我做错了什么 mysql gt select d
  • Java Signature.verify 导致 SignatureException:签名编码错误 由 IOException 引起:序列标记错误

    首先 这不是一个重复的问题 因为大多数人在从缺少 BEGIN RSA CERTIFICATE 行的证书创建公钥时报告此异常 我想做的要点是 1 使用 SHA1withRSA 算法 RSA 密钥为 1024 位 在 JCOP 智能卡上签署 5
  • 使用 JavaScript 设置 HTML 页面垂直位置

    我有一个可以上下滚动的 HTML 页面 不是很多 但确实可以滚动 执行一些 JavaScript 后如何设置页面中的滚动位置 我正在使用 jQuery 在页面底部注入一些额外的 HTML 并且我想在添加新内容后以编程方式滚动到新内容的位置
  • 在 ASP.NET Core 上实现“Fire and Forget”方法的安全方法

    我正在尝试实现一个简单的日志记录库 该库将在多个项目中使用 库的工作是将 HTTP 请求发送到 ElasticSearch 这个库的要点是它不能等待响应 另外 我不关心任何错误 异常 它必须将请求发送到 ElasticSearch 并立即返