[Abp vNext 源码分析] - 12. 后台作业与后台工作者 (2)

这里对 _performingTasks 和 _isRunning 字段设置为 volatile 防止指令重排和寄存器缓存。这是因为在 Stop 方法内部使用到的 _performingTasks 可能会被优化,所以将该字段设置为了易失的。

2.2.1 IRunnable 接口

ABP vNext 为任务的启动和停止,抽象了一个 IRunnable 接口。虽然描述说的是对线程的行为进行抽象,但千万千万不要手动调用 Thread.Abort() 。关于 Thread.Abort() 的坏处,这里不再多加赘述,可以参考 的描述,或者搜索其他的相关文章。

public interface IRunnable { // 启动这个服务。 Task StartAsync(CancellationToken cancellationToken = default); /// <summary> /// 停止这个服务。 /// </summary> Task StopAsync(CancellationToken cancellationToken = default); } 2.2 后台工作者 2.2.1 模块的构造

后台工作者的模块行为比较简单,它定义了在应用程序初始化和销毁时的行为。在初始化时,后台工作者管理器 获得所有 后台工作者,并开始启动它们。在销毁时,后台工作者管理器获得所有后台工作者,并开始停止他们,这样才能够做到优雅退出。

[DependsOn( typeof(AbpThreadingModule) )] public class AbpBackgroundWorkersModule : AbpModule { public override void OnApplicationInitialization(ApplicationInitializationContext context) { var options = context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundWorkerOptions>>().Value; // 如果启用了后台工作者,那么获得后台工作者管理器的实例,并调用 StartAsync 启动所有后台工作者。 if (options.IsEnabled) { AsyncHelper.RunSync( () => context.ServiceProvider .GetRequiredService<IBackgroundWorkerManager>() .StartAsync() ); } } public override void OnApplicationShutdown(ApplicationShutdownContext context) { var options = context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundWorkerOptions>>().Value; // 如果启用了后台工作者,那么获得后台工作者管理器的实例,并调用 StopAsync 停止所有后台工作者。 if (options.IsEnabled) { AsyncHelper.RunSync( () => context.ServiceProvider .GetRequiredService<IBackgroundWorkerManager>() .StopAsync() ); } } } 2.2.1 后台工作者的定义

首先看看 IBackgroundWorker 接口的定义,是空的。不过继承了 ISingletonDependency 接口,说明我们的每个后台工作者都是 单例 的。

/// <summary> /// 在后台运行,执行某些任务的工作程序(线程)的接口定义。 /// </summary> public interface IBackgroundWorker : IRunnable, ISingletonDependency { }

ABP vNext 为我们定义了一个抽象的后台工作者类型 BackgroundWorkerBase,这个基类的设计目的是提供一些常用组件(和 ApplicationService 一样)。

public abstract class BackgroundWorkerBase : IBackgroundWorker { //TODO: Add UOW, Localization and other useful properties..? //TODO: 是否应该提供工作单元、本地化以及其他常用的属性? public ILogger<BackgroundWorkerBase> Logger { protected get; set; } protected BackgroundWorkerBase() { Logger = NullLogger<BackgroundWorkerBase>.Instance; } public virtual Task StartAsync(CancellationToken cancellationToken = default) { Logger.LogDebug("Started background worker: " + ToString()); return Task.CompletedTask; } public virtual Task StopAsync(CancellationToken cancellationToken = default) { Logger.LogDebug("Stopped background worker: " + ToString()); return Task.CompletedTask; } public override string ToString() { return GetType().FullName; } }

ABP vNext 内部只有一个默认的后台工作者实现 PeriodicBackgroundWorkerBase。从名字上来看,意思是就是周期执行的后台工作者,内部就是用的 AbpTimer 来实现,ABP vNext 将其包装起来是为了实现统一的模式(后台工作者)。

public abstract class PeriodicBackgroundWorkerBase : BackgroundWorkerBase { protected readonly AbpTimer Timer; // 也就意味着子类必须在其构造函数,指定 timer 的执行周期。 protected PeriodicBackgroundWorkerBase(AbpTimer timer) { Timer = timer; Timer.Elapsed += Timer_Elapsed; } // 启动后台工作者。 public override async Task StartAsync(CancellationToken cancellationToken = default) { await base.StartAsync(cancellationToken); Timer.Start(cancellationToken); } // 停止后台工作者。 public override async Task StopAsync(CancellationToken cancellationToken = default) { Timer.Stop(cancellationToken); await base.StopAsync(cancellationToken); } // Timer 关联的周期事件,之所以不直接挂载 DoWork,是为了捕获异常。 private void Timer_Elapsed(object sender, System.EventArgs e) { try { DoWork(); } catch (Exception ex) { Logger.LogException(ex); } } // 你要周期执行的任务。 protected abstract void DoWork(); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsfpgd.html