mirror of https://github.com/abpframework/abp
Merge branch 'dev' of https://github.com/abpframework/abp into dev
commit
460432271a
@ -1,3 +1,140 @@
|
|||||||
# Background Workers
|
# Background Workers
|
||||||
|
|
||||||
TODO
|
## Introduction
|
||||||
|
|
||||||
|
Background workers are simple independent threads in the application running in the background. Generally, they run periodically to perform some tasks. Examples;
|
||||||
|
|
||||||
|
* A background worker can run periodically to **delete old logs**.
|
||||||
|
* A background worker can run periodically to **determine inactive users** and **send emails** to get users to return to your application.
|
||||||
|
|
||||||
|
|
||||||
|
## Create a Background Worker
|
||||||
|
|
||||||
|
A background worker should directly or indirectly implement the `IBackgroundWorker` interface.
|
||||||
|
|
||||||
|
> A background worker is inherently [singleton](Dependency-Injection.md). So, only a single instance of your worker class is instantiated and run.
|
||||||
|
|
||||||
|
### BackgroundWorkerBase
|
||||||
|
|
||||||
|
`BackgroundWorkerBase` is an easy way to create a background worker.
|
||||||
|
|
||||||
|
````csharp
|
||||||
|
public class MyWorker : BackgroundWorkerBase
|
||||||
|
{
|
||||||
|
public override Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task StopAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
Start your worker in the `StartAsync` (which is called when the application begins) and stop in the `StopAsync` (which is called when the application shuts down).
|
||||||
|
|
||||||
|
> You can directly implement the `IBackgroundWorker`, but `BackgroundWorkerBase` provides some useful properties like `Logger`.
|
||||||
|
|
||||||
|
### AsyncPeriodicBackgroundWorkerBase
|
||||||
|
|
||||||
|
Assume that we want to make a user passive, if the user has not logged in to the application in last 30 days. `AsyncPeriodicBackgroundWorkerBase` class simplifies to create periodic workers, so we will use it for the example below:
|
||||||
|
|
||||||
|
````csharp
|
||||||
|
public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
|
||||||
|
{
|
||||||
|
public PassiveUserCheckerWorker(
|
||||||
|
AbpTimer timer,
|
||||||
|
IServiceScopeFactory serviceScopeFactory
|
||||||
|
) : base(
|
||||||
|
timer,
|
||||||
|
serviceScopeFactory)
|
||||||
|
{
|
||||||
|
Timer.Period = 600000; //10 minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task DoWorkAsync(
|
||||||
|
PeriodicBackgroundWorkerContext workerContext)
|
||||||
|
{
|
||||||
|
Logger.LogInformation("Starting: Setting status of inactive users...");
|
||||||
|
|
||||||
|
//Resolve dependencies
|
||||||
|
var userRepository = workerContext
|
||||||
|
.ServiceProvider
|
||||||
|
.GetRequiredService<IUserRepository>();
|
||||||
|
|
||||||
|
//Do the work
|
||||||
|
await userRepository.UpdateInactiveUserStatusesAsync();
|
||||||
|
|
||||||
|
Logger.LogInformation("Completed: Setting status of inactive users...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
* `AsyncPeriodicBackgroundWorkerBase` uses the `AbpTimer` (a thread-safe timer) object to determine **the period**. We can set its `Period` property in the constructor.
|
||||||
|
* It required to implement the `DoWorkAsync` method to **execute** the periodic work.
|
||||||
|
* It is a good practice to **resolve dependencies** from the `PeriodicBackgroundWorkerContext` instead of constructor injection. Because `AsyncPeriodicBackgroundWorkerBase` uses a `IServiceScope` that is **disposed** when your work finishes.
|
||||||
|
* `AsyncPeriodicBackgroundWorkerBase` **catches and logs exceptions** thrown by the `DoWorkAsync` method.
|
||||||
|
|
||||||
|
|
||||||
|
## Register Background Worker
|
||||||
|
|
||||||
|
After creating a background worker class, you should to add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class:
|
||||||
|
|
||||||
|
````csharp
|
||||||
|
[DependsOn(typeof(AbpBackgroundWorkersModule))]
|
||||||
|
public class MyModule : AbpModule
|
||||||
|
{
|
||||||
|
public override void OnApplicationInitialization(
|
||||||
|
ApplicationInitializationContext context)
|
||||||
|
{
|
||||||
|
context.AddBackgroundWorker<PassiveUserCheckerWorker>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
`context.AddBackgroundWorker(...)` is a shortcut extension method for the expression below:
|
||||||
|
|
||||||
|
````
|
||||||
|
context.ServiceProvider
|
||||||
|
.GetRequiredService<IBackgroundWorkerManager>()
|
||||||
|
.Add(
|
||||||
|
context
|
||||||
|
.ServiceProvider
|
||||||
|
.GetRequiredService<PassiveUserCheckerWorker>()
|
||||||
|
);
|
||||||
|
````
|
||||||
|
|
||||||
|
So, it resolves the given background worker and adds to the `IBackgroundWorkerManager`.
|
||||||
|
|
||||||
|
While we generally add workers in `OnApplicationInitialization`, there are no restrictions on that. You can inject `IBackgroundWorkerManager` anywhere and add workers at runtime. Background worker manager will stop and release all the registered workers when your application is being shut down.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
`AbpBackgroundWorkerOptions` class is used to [set options](Options.md) for the background workers. Currently, there is only one option:
|
||||||
|
|
||||||
|
* `IsEnabled` (default: true): Used to **enable/disable** the background worker system for your application.
|
||||||
|
|
||||||
|
> See the [Options](Options.md) document to learn how to set options.
|
||||||
|
|
||||||
|
## Making Your Application Always Run
|
||||||
|
|
||||||
|
Background workers only work if your application is running. If you host the background job execution in your web application (this is the default behavior), you should ensure that your web application is configured to always be running. Otherwise, background jobs only work while your application is in use.
|
||||||
|
|
||||||
|
## Running On a Cluster
|
||||||
|
|
||||||
|
Be careful if you run multiple instances of your application simultaneously in a clustered environment. In that case, every application runs the same worker which may create conflicts if your workers are running on the same resources (processing the same data, for example).
|
||||||
|
|
||||||
|
If that's a problem for your workers, you have two options;
|
||||||
|
|
||||||
|
* Disable the background worker system using the `AbpBackgroundWorkerOptions` described above, for all the application instances, except one of them.
|
||||||
|
* Disable the background worker system for all the application instances and create another special application that runs on a single server and execute the workers.
|
||||||
|
|
||||||
|
## Quartz Integration
|
||||||
|
|
||||||
|
ABP Framework's background worker system is good to implement periodic tasks. However, you may want to use an advanced task scheduler like [Quartz](https://www.quartz-scheduler.net/). See the community contributed [quartz integration](Background-Workers-Quartz.md) for the background workers.
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
* [Quartz Integration for the background workers](Background-Workers-Quartz.md)
|
||||||
|
* [Background Jobs](Background-Jobs.md)
|
@ -0,0 +1,3 @@
|
|||||||
|
# ASP.NET Boilerplate v5+ 迁移到 ABP Framework
|
||||||
|
|
||||||
|
TODO...
|
@ -0,0 +1,3 @@
|
|||||||
|
# 自定义应用模块: 扩展实体
|
||||||
|
|
||||||
|
TODO...
|
@ -0,0 +1,62 @@
|
|||||||
|
# 自定义现有模块
|
||||||
|
|
||||||
|
ABP框架提供的设计旨在支持构建完全[模块化的应用程序](Module-Development-Basics.md)和系统. 它还提供了一些可以在任何类型的应用程序中**使用**的[预构建应用模块](Modules/Index.md)
|
||||||
|
|
||||||
|
例如,你可以在你的应用程序中**重用**[身份管理模块](Modules/Identity.md)去添加用户,角色和权限管理. [应用程序启动模板](Startup-Templates/Application.md)已经**预装**了Identity和其他模块.
|
||||||
|
|
||||||
|
## 复用应用模块
|
||||||
|
|
||||||
|
你有两个选项去复用应用模块:
|
||||||
|
|
||||||
|
### 添加包引用
|
||||||
|
|
||||||
|
你可以添加相关模块的 **NuGet** 和 **NPM** 包引用到你的应用程序,并配置模块(根据它的文档)集成到你的应用程序中.
|
||||||
|
|
||||||
|
正如前面提到,[应用程序启动模板](Startup-Templates/Application.md)已经**预装了一些基本模块**,它引用模块的NuGet和NPM包.
|
||||||
|
|
||||||
|
这种方法具有以下优点:
|
||||||
|
|
||||||
|
* 你的解决方案会非常**干净**,只包含你**自己的应用程序代码**.
|
||||||
|
* 你可以**很简单的**升级模块到最新的可用模板. `abp update` [CLI](CLI.md) 命令会使更新变的更加简单. 通过这种方式, 你可以获得**最新功能和Bus修复**.
|
||||||
|
|
||||||
|
然而有一个缺点:
|
||||||
|
|
||||||
|
* 你可能无法**自定义**模块,因为模块源码没有在你的解决方案中.
|
||||||
|
|
||||||
|
本文档介绍了 **或者自定义或扩展** 依赖模块并且无需更改其源码,尽快与更改完整的源码比起是有限的,但仍有一些好的方法可以自定义.
|
||||||
|
|
||||||
|
如果你不认为自己会对预构建的模块进行重大更改,那么使用包引用的方法复用模块是推荐的方法.
|
||||||
|
|
||||||
|
### 包含源码
|
||||||
|
|
||||||
|
如果你想要在预构建的模块上进行**重大**更改或添加**主要功能**,但是可用的扩展点不够使用,那么可以考虑直接使用依赖模块的源码.
|
||||||
|
|
||||||
|
这种情况下,你通常**添加模块源码**到你的解决方案中,并将**包引用替换**为本地项目引用. **[ABP CLI](CLI.md)** 可以为你自动化这一过程.
|
||||||
|
|
||||||
|
#### 分离模块解决方案
|
||||||
|
|
||||||
|
你可能不希望将模块源代码**直接包含在解决方案**中. 每个模块都包含十多个项目文件,添加**多个模块**会使解决方案变的臃肿可能还会影响**开发时的加载速度**,另外你可能有不同的开发团队维护不同模块.
|
||||||
|
|
||||||
|
无论如何,你都可以为需要的模块创建**单独的解决方案**,将依赖模块做为解决方案中的项目引用. 比如在[abp仓库](https://github.com/abpframework/abp/),我们就是这样做的.
|
||||||
|
|
||||||
|
> 我们看到的一个问题是Visual Studio在这种方式下不能很好的工作(解决方案目录之外对本地项目的引用不能很好地支持). 如果在开发过程中出错(对于外部模块),请在Visual Studio打开应用程序的解决方案后,在命令行运行 `dotnet restore`命令.
|
||||||
|
|
||||||
|
#### 发布的自定义模块的包
|
||||||
|
|
||||||
|
一个备选方案是将重新打包模块的源代码(NuGet/NPM包),使用包引用. 你可以为公司使用本地私人的Nuget/NPM服务器.
|
||||||
|
|
||||||
|
## 模块自定义/扩展途径
|
||||||
|
|
||||||
|
如果你决定使用预构建模块的NuGet/NPM包引用方式. 下面的文档详细解释了如何自定义/扩展现有模块的方法:
|
||||||
|
|
||||||
|
* [扩展实体](Customizing-Application-Modules-Extending-Entities.md)
|
||||||
|
* [重写服务](Customizing-Application-Modules-Overriding-Services.md)
|
||||||
|
* [重写界面](Customizing-Application-Modules-Overriding-User-Interface.md)
|
||||||
|
|
||||||
|
### 另请参阅
|
||||||
|
|
||||||
|
另外,请参阅以下文档:
|
||||||
|
|
||||||
|
* 参阅 [本地化文档](Localization.md) 学习如何扩展已存在的本地化资源.
|
||||||
|
* 参阅 [设置文档](Settings.md) 学习如何更改依赖模块的设置定义.
|
||||||
|
* 参阅 [授权文档](Authorization.md) 学习如何更改依赖模块的权限定义.
|
@ -0,0 +1,3 @@
|
|||||||
|
# 自定义应用模块: 覆盖服务
|
||||||
|
|
||||||
|
TODO...
|
@ -0,0 +1,6 @@
|
|||||||
|
# 重写用户界面
|
||||||
|
|
||||||
|
你可以想要重写页面,组件,JavaScript,CSS或你依赖模块的图片文件. 重写UI取决于你使用的UI框架. 选择UI框架以继续:
|
||||||
|
|
||||||
|
* [ASP.NET Core (MVC / Razor Pages)](UI/AspNetCore/Customization-User-Interface.md)
|
||||||
|
* [Angular](UI/Angular/Customization-User-Interface.md)
|
@ -0,0 +1,3 @@
|
|||||||
|
# ASP.NET Core (MVC / Razor Pages) 用户界面自定义指南
|
||||||
|
|
||||||
|
TODO...
|
Loading…
Reference in new issue