如何为特定的后台任务确定静态类对象的范围?

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 中为jobNameuserId,...并在每个服务中使用此信息在scope 中被调用,可能类似于AppConfig.currentJob.jobname.userId,因为需要一些表来标记用户日志信息。 我们已经测试过这个解决方案并且它确实有效。但是要保证这种行为是否正确,我们是否需要,我们的知识仍然有限。我们已尝试将 IHostedService 作为问题的 cmets。但是您的回答确实对我们有帮助,非常感谢。 @sambath999:如果你需要它用于日志记录,那么我推荐ILogger.BeginScope

以上是关于如何为特定的后台任务确定静态类对象的范围?的主要内容,如果未能解决你的问题,请参考以下文章

特定时间的离子后台任务?

SBT - 如何为特定任务禁用插件(例如“包”)

如何显示屏幕并运行一些“后台”任务(不使用线程)

在特定时间运行后台任务 - Windows 10 App

PHP 获取 特定时间范围 类

从后台任务或服务中确定当前前台应用程序