如何为特定的后台任务确定静态类对象的范围?
Posted
技术标签:
【中文标题】如何为特定的后台任务确定静态类对象的范围?【英文标题】:How to scope static class object for specific background task? 【发布时间】:2021-12-26 11:14:18 【问题描述】:考虑
public class BackgroundJob
public string jobNameget;set;
...
AppConfig.cs
public class AppConfig
public static BackgroundJob currentJobget;set;
BackgroundjobService.cs
public interface IBackgroundJobService
...
public class BackgroundJobService : IBackgroundJobService
private readonly ServiceScopFactory _serviceScopFactory;
public BackgroundJobService(ServiceScopFactory serviceScopFactory)
_serviceScopFactory = serviceScopFactory;
public async Task RunBackgroundJobTest1()
using (var serviceScope = _serviceScopeFactory.CreateScope())
AppConfig.currentJob = new() jobName = "job1" ;
var idx = 0;
for (int i = 0; i <= 1000; i += 100)
idx++;
await Task.Delay(1000);
Console.WriteLine($"===> jobName = currentJob.jobname");
public async Task RunBackgroundJobTest2()
using (var serviceScope = _serviceScopeFactory.CreateScope())
AppConfig.currentJob = new() jobName = "job2" ;
var idx = 0;
for (int i = 0; i <= 1000; i += 100)
idx++;
await Task.Delay(1000);
Console.WriteLine($"===> jobName = currentJob.jobname");
执行:
public class TestController : Controller
private readonly IBackgroundJobClient _backgroundJobClient; //hangfire
public TestController(IBackgroundJobClient backgroundJobClient)
_backgroundJobClient = backgroundJobClient;
[HttpGet("test")]
public IActionResult Test()
_backgroundJobClient.Enqueue<IBackgroundJobService>(x=>x.RunBackgroundJobTest1()); //log ===> jobName = job2
_backgroundJobClient.Enqueue<IBackgroundJobService>(x=>x.RunBackgroundJobTest2()); //log ===> jobName = job2
因此,AppConfig.currentJob
不会保留ServiceScop1
内部/内部的第一个值,而是由ServiceScope2
内部的最后一个任务重新初始化
问题: 有人建议我为此目的正确实施吗? 我们将不胜感激。谢谢
【问题讨论】:
如何为特定后台任务设置静态类对象的范围 - 不要使用static
,而是为每个范围创建新实例。
您可能使用[ThreadStatic]
解决它,但是如果任务调度程序在同一个线程上连续运行作业,这将很难找到错误。您要求正确的实现,但我认为您的 BackgroundJobService
也应该受到审查。为什么你自己滚动而不使用IHostedService
?
@Fabio 感谢您的快速响应,但我们需要将其用作全局,这意味着在 serviceScope 内调用的其他服务也可以访问此object
,而无需将参数作为参数传递给被调用的那些。
@CodeCaster 谢谢先生。由于我对长时间运行任务的后台作业的了解仍然有限,因此在您告诉我 IHostedService 之前,我已经阅读了有关使用 ServiceScopeFactory 的信息。当然,我需要正确的实施,很高兴收到您的建议。
【参考方案1】:
我不清楚您要达到的目标。无论如何,据我了解您的问题,您可以尝试下面的代码。 它将使 currentJob 本地化到您的处理中。与 [ThreadStatic] 不同,如果进程更改线程,这不会失败:
public class AppConfig
private static System.Threading.AsyncLocal<BackgroundJob> _currentJob get;
= new System.Threading.AsyncLocal<BackgroundJob>();
public static BackgroundJob currentJob
get return _currentJob.Value;
set _currentJob.Value = value;
请注意,此行为未链接到 ScopeServiceFactories。要拥有完整的依赖注入,链接到你需要删除静态的作用域。
【讨论】:
谢谢!我们很抱歉您的回答迟了一点。对于这个问题,即我们正在测试长时间运行的任务,在运行时我们认为我们应该将objects
存储在当前运行范围global object
中为jobName
、userId
,...并在每个服务中使用此信息在scope
中被调用,可能类似于AppConfig.currentJob.jobname
、.userId
,因为需要一些表来标记用户日志信息。
我们已经测试过这个解决方案并且它确实有效。但是要保证这种行为是否正确,我们是否需要,我们的知识仍然有限。我们已尝试将 IHostedService
作为问题的 cmets。但是您的回答确实对我们有帮助,非常感谢。
@sambath999:如果你需要它用于日志记录,那么我推荐ILogger.BeginScope
。以上是关于如何为特定的后台任务确定静态类对象的范围?的主要内容,如果未能解决你的问题,请参考以下文章