Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ff29dd0
Initial plan
Copilot Sep 28, 2025
bdcc697
Add TickerQ background worker integration
Copilot Sep 28, 2025
071ef3b
Complete TickerQ integration with tests, samples, and documentation
Copilot Sep 28, 2025
e21a776
Add net10.0 target framework to TickerQ projects
Copilot Sep 29, 2025
e01916d
Merge branch 'dev' into copilot/fix-d5496b38-0efc-4016-8ab2-970b67675314
maliming Oct 1, 2025
4177061
feat: Introduce TickerQ background job integration
maliming Oct 4, 2025
94ac0d4
Merge branch 'dev' into copilot/fix-d5496b38-0efc-4016-8ab2-970b67675314
maliming Oct 4, 2025
3a9f035
feat: Implement TickerQ background worker management.
maliming Oct 5, 2025
ff2c239
Remove TickerQ background worker test project
maliming Oct 5, 2025
4a9f302
feat: Add TickerQ background job support and related modules
maliming Oct 5, 2025
b0a1a6b
feat: Add TickerQ integration to documentation and demo module
maliming Oct 5, 2025
5e23008
Add configurable retry options for TickerQ background jobs
maliming Oct 5, 2025
eff20f2
Add MyBackgroundWorker demo.
maliming Oct 5, 2025
fab7139
Add free disk space step to CI workflow
maliming Oct 5, 2025
2ada873
Move free-disk-space step before checkout in CI
maliming Oct 5, 2025
2750b3a
Add TickerQ dashboard integration to demo app
maliming Oct 5, 2025
185829f
Add priority support to TickerQ job configuration
maliming Oct 5, 2025
9c69d34
Add TickerQ job configuration and dashboard docs
maliming Oct 5, 2025
14c54c4
Refactor TickerQ managers and add worker configuration support
maliming Oct 5, 2025
91f7774
Rename jobType to workerType in options class
maliming Oct 5, 2025
ca4bd0e
Remove ExposeServices attribute from worker manager
maliming Oct 5, 2025
7149673
Optimize TickerQ background job and worker invocation
maliming Oct 6, 2025
c1b6557
Handling conflicts.
maliming Oct 6, 2025
6aa0528
Update docs-nav.json
EngincanV Oct 6, 2025
76300f4
Fix path separator in solution file and improve docs
EngincanV Oct 6, 2025
e8359d1
Remove manual installation steps from TickerQ docs
maliming Oct 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@ jobs:
timeout-minutes: 50
if: ${{ !github.event.pull_request.draft }}
steps:
- uses: jlumbroso/free-disk-space@main
- uses: PSModule/install-powershell@v1
with:
Version: latest
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@master
with:
dotnet-version: 10.0.x

- name: Build All
run: ./build-all.ps1
working-directory: ./build
Expand Down
4 changes: 4 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
<PackageVersion Include="TencentCloudSDK.Sms" Version="3.0.1273" />
<PackageVersion Include="TimeZoneConverter" Version="7.0.0" />
<PackageVersion Include="TickerQ" Version="2.5.3" />
<PackageVersion Include="TickerQ.Dashboard" Version="2.5.3" />
<PackageVersion Include="TickerQ.Utilities" Version="2.5.3" />
<PackageVersion Include="TickerQ.EntityFrameworkCore" Version="2.5.3" />
<PackageVersion Include="Unidecode.NET" Version="2.1.0" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.extensibility.execution" Version="2.9.3" />
Expand Down
8 changes: 8 additions & 0 deletions docs/en/docs-nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,10 @@
{
"text": "Quartz Integration",
"path": "framework/infrastructure/background-jobs/quartz.md"
},
{
"text": "TickerQ Integration",
"path": "framework/infrastructure/background-jobs/tickerq.md"
}
]
},
Expand All @@ -589,6 +593,10 @@
{
"text": "Hangfire Integration",
"path": "framework/infrastructure/background-workers/hangfire.md"
},
{
"text": "TickerQ Integration",
"path": "framework/infrastructure/background-workers/tickerq.md"
}
]
},
Expand Down
1 change: 1 addition & 0 deletions docs/en/framework/infrastructure/background-jobs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ See pre-built job manager alternatives:
* [Hangfire Background Job Manager](./hangfire.md)
* [RabbitMQ Background Job Manager](./rabbitmq.md)
* [Quartz Background Job Manager](./quartz.md)
* [TickerQ Background Job Manager](./tickerq.md)

## See Also
* [Background Workers](../background-workers)
125 changes: 125 additions & 0 deletions docs/en/framework/infrastructure/background-jobs/tickerq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# TickerQ Background Job Manager

[TickerQ](https://tickerq.net/) is a fast, reflection-free background task scheduler for .NET — built with source generators, EF Core integration, cron + time-based execution, and a real-time dashboard. You can integrate TickerQ with the ABP to use it instead of the [default background job manager](../background-jobs). In this way, you can use the same background job API for TickerQ and your code will be independent of TickerQ. If you like, you can directly use TickerQ's API, too.

> See the [background jobs document](../background-jobs) to learn how to use the background job system. This document only shows how to install and configure the TickerQ integration.
## Installation

It is suggested to use the [ABP CLI](../../../cli) to install this package.

### Using the ABP CLI

Open a command line window in the folder of the project (.csproj file) and type the following command:

````bash
abp add-package Volo.Abp.BackgroundJobs.TickerQ
````

> If you haven't done it yet, you first need to install the [ABP CLI](../../../cli). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.BackgroundJobs.TickerQ).
## Configuration

### AddTickerQ

You can call the `AddTickerQ` extension method in the `ConfigureServices` method of your module to configure TickerQ services:

> This is optional. ABP will automatically register TickerQ services.
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTickerQ(x =>
{
// Configure TickerQ options here
});
}
```

### UseAbpTickerQ

You need to call the `UseAbpTickerQ` extension method instead of `AddTickerQ` in the `OnApplicationInitialization` method of your module:

```csharp
// (default: TickerQStartMode.Immediate)
app.UseAbpTickerQ(startMode: ...);
```

### AbpBackgroundJobsTickerQOptions

You can configure the `TimeTicker` properties for specific jobs. For example, you can change `Priority`, `Retries` and `RetryIntervals` properties as shown below:

```csharp
Configure<AbpBackgroundJobsTickerQOptions>(options =>
{
options.AddJobConfiguration<MyBackgroundJob>(new AbpBackgroundJobsTimeTickerConfiguration()
{
Retries = 3,
RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min
Priority = TickerTaskPriority.High

// Optional batching
//BatchParent = Guid.Parse("...."),
//BatchRunCondition = BatchRunCondition.OnSuccess
});

options.AddJobConfiguration<MyBackgroundJob2>(new AbpBackgroundJobsTimeTickerConfiguration()
{
Retries = 5,
RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min
Priority = TickerTaskPriority.Normal
});
});
```

### Add your own TickerQ Background Jobs Definitions

ABP will handle the TickerQ job definitions by `AbpTickerQFunctionProvider` service. You shouldn't use `TickerFunction` to add your own job definitions. You can inject and use the `AbpTickerQFunctionProvider` to add your own definitions and use `ITimeTickerManager<TimeTicker>` or `ICronTickerManager<CronTicker>` to manage the jobs.

For example, you can add a `CleanupJobs` job definition in the `OnPreApplicationInitializationAsync` method of your module:

```csharp
public class CleanupJobs
{
public async Task CleanupLogsAsync(TickerFunctionContext<string> tickerContext, CancellationToken cancellationToken)
{
var logFileName = tickerContext.Request;
Console.WriteLine($"Cleaning up log file: {logFileName} at {DateTime.Now}");
}
}
```

```csharp
public override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
{
var abpTickerQFunctionProvider = context.ServiceProvider.GetRequiredService<AbpTickerQFunctionProvider>();
abpTickerQFunctionProvider.Functions.TryAdd(nameof(CleanupJobs), (string.Empty, TickerTaskPriority.Normal, new TickerFunctionDelegate(async (cancellationToken, serviceProvider, tickerFunctionContext) =>
{
var service = new CleanupJobs(); // Or get it from the serviceProvider
var request = await TickerRequestProvider.GetRequestAsync<string>(serviceProvider, tickerFunctionContext.Id, tickerFunctionContext.Type);
var genericContext = new TickerFunctionContext<string>(tickerFunctionContext, request);
await service.CleanupLogsAsync(genericContext, cancellationToken);
})));
abpTickerQFunctionProvider.RequestTypes.TryAdd(nameof(CleanupJobs), (typeof(string).FullName, typeof(string)));
return Task.CompletedTask;
}
```

And then you can add a job by using the `ITimeTickerManager<TimeTicker>`:

```csharp
var timeTickerManager = context.ServiceProvider.GetRequiredService<ITimeTickerManager<TimeTicker>>();
await timeTickerManager.AddAsync(new TimeTicker
{
Function = nameof(CleanupJobs),
ExecutionTime = DateTime.UtcNow.AddSeconds(5),
Request = TickerHelper.CreateTickerRequest<string>("cleanup_example_file.txt"),
Retries = 3,
RetryIntervals = new[] { 30, 60, 120 }, // Retry after 30s, 60s, then 2min
});
```

### TickerQ Dashboard and EF Core Integration

You can install the [TickerQ dashboard](https://tickerq.net/setup/dashboard.html) and [Entity Framework Core](https://tickerq.net/setup/tickerq-ef-core.html) integration by its documentation. There is no specific configuration needed for the ABP integration.

5 changes: 3 additions & 2 deletions docs/en/framework/infrastructure/background-workers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Start your worker in the `StartAsync` (which is called when the application begi

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:

> You can use `CronExpression` property to set the cron expression for the background worker if you will use the [Hangfire Background Worker Manager](./hangfire.md) or [Quartz Background Worker Manager](./quartz.md).
> You can use `CronExpression` property to set the cron expression for the background worker if you will use the [Hangfire Background Worker Manager](./hangfire.md), [Quartz Background Worker Manager](./quartz.md), or [TickerQ Background Worker Manager](./tickerq.md).
````csharp
public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
Expand Down Expand Up @@ -216,7 +216,8 @@ Background worker system is extensible and you can change the default background
See pre-built worker manager alternatives:

* [Quartz Background Worker Manager](./quartz.md)
* [Hangfire Background Worker Manager](./hangfire.md)
* [Hangfire Background Worker Manager](./hangfire.md)
* [TickerQ Background Worker Manager](./tickerq.md)

## See Also

Expand Down
119 changes: 119 additions & 0 deletions docs/en/framework/infrastructure/background-workers/tickerq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# TickerQ Background Worker Manager

[TickerQ](https://tickerq.net/) is a fast, reflection-free background task scheduler for .NET — built with source generators, EF Core integration, cron + time-based execution, and a real-time dashboard. You can integrate TickerQ with the ABP to use it instead of the [default background worker manager](../background-workers).

## Installation

It is suggested to use the [ABP CLI](../../../cli) to install this package.

### Using the ABP CLI

Open a command line window in the folder of the project (.csproj file) and type the following command:

````bash
abp add-package Volo.Abp.BackgroundWorkers.TickerQ
````

> If you haven't done it yet, you first need to install the [ABP CLI](../../../cli). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.BackgroundWorkers.TickerQ).
## Configuration

### AddTickerQ

You can call the `AddTickerQ` extension method in the `ConfigureServices` method of your module to configure TickerQ services:

> This is optional. ABP will automatically register TickerQ services.
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTickerQ(x =>
{
// Configure TickerQ options here
});
}
```

### UseAbpTickerQ

You need to call the `UseAbpTickerQ` extension method instead of `AddTickerQ` in the `OnApplicationInitialization` method of your module:

```csharp
// (default: TickerQStartMode.Immediate)
app.UseAbpTickerQ(startMode: ...);
```

### AbpBackgroundWorkersTickerQOptions

You can configure the `CronTicker` properties for specific jobs. For example, Change `Priority`, `Retries` and `RetryIntervals` properties:

```csharp
Configure<AbpBackgroundWorkersTickerQOptions>(options =>
{
options.AddConfiguration<MyBackgroundWorker>(new AbpBackgroundWorkersCronTickerConfiguration()
{
Retries = 3,
RetryIntervals = new[] {30, 60, 120}, // Retry after 30s, 60s, then 2min,
Priority = TickerTaskPriority.High
});
});
```

### Add your own TickerQ Background Worker Definitions

ABP will handle the TickerQ job definitions by `AbpTickerQFunctionProvider` service. You shouldn't use `TickerFunction` to add your own job definitions. You can inject and use the `AbpTickerQFunctionProvider` to add your own definitions and use `ITimeTickerManager<TimeTicker>` or `ICronTickerManager<CronTicker>` to manage the jobs.

For example, you can add a `CleanupJobs` job definition in the `OnPreApplicationInitializationAsync` method of your module:

```csharp
public class CleanupJobs
{
public async Task CleanupLogsAsync(TickerFunctionContext<string> tickerContext, CancellationToken cancellationToken)
{
var logFileName = tickerContext.Request;
Console.WriteLine($"Cleaning up log file: {logFileName} at {DateTime.Now}");
}
}
```

```csharp
public override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
{
var abpTickerQFunctionProvider = context.ServiceProvider.GetRequiredService<AbpTickerQFunctionProvider>();
abpTickerQFunctionProvider.Functions.TryAdd(nameof(CleanupJobs), (string.Empty, TickerTaskPriority.Normal, new TickerFunctionDelegate(async (cancellationToken, serviceProvider, tickerFunctionContext) =>
{
var service = new CleanupJobs(); // Or get it from the serviceProvider
var request = await TickerRequestProvider.GetRequestAsync<string>(serviceProvider, tickerFunctionContext.Id, tickerFunctionContext.Type);
var genericContext = new TickerFunctionContext<string>(tickerFunctionContext, request);
await service.CleanupLogsAsync(genericContext, cancellationToken);
})));
abpTickerQFunctionProvider.RequestTypes.TryAdd(nameof(CleanupJobs), (typeof(string).FullName, typeof(string)));
return Task.CompletedTask;
}
```

And then you can add a job by using the `ICronTickerManager<CronTicker>`:

```csharp
var cronTickerManager = context.ServiceProvider.GetRequiredService<ICronTickerManager<CronTicker>>();
await cronTickerManager.AddAsync(new CronTicker
{
Function = nameof(CleanupJobs),
Expression = "0 */6 * * *", // Every 6 hours
Request = TickerHelper.CreateTickerRequest<string>("cleanup_example_file.txt"),
Retries = 2,
RetryIntervals = new[] { 60, 300 }
});
```

You can specify a cron expression instead of use `ICronTickerManager<CronTicker>` to add a worker:

```csharp
abpTickerQFunctionProvider.Functions.TryAdd(nameof(CleanupJobs), (string.Empty, TickerTaskPriority.Normal, new TickerFunctionDelegate(async (cancellationToken, serviceProvider, tickerFunctionContext) =>
{
var service = new CleanupJobs();
var request = await TickerRequestProvider.GetRequestAsync<string>(serviceProvider, tickerFunctionContext.Id, tickerFunctionContext.Type);
var genericContext = new TickerFunctionContext<string>(tickerFunctionContext, request);
await service.CleanupLogsAsync(genericContext, cancellationToken);
})));
```
5 changes: 4 additions & 1 deletion framework/Volo.Abp.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@
<Project Path="src/Volo.Abp/Volo.Abp.csproj" />
<Project Path="src/Volo.Abp.AI.Abstractions/Volo.Abp.AI.Abstractions.csproj" />
<Project Path="src/Volo.Abp.AI/Volo.Abp.AI.csproj" />
<Project Path="src/Volo.Abp.TickerQ/Volo.Abp.TickerQ.csproj" />
<Project Path="src/Volo.Abp.BackgroundJobs.TickerQ/Volo.Abp.BackgroundJobs.TickerQ.csproj" />
<Project Path="src/Volo.Abp.BackgroundWorkers.TickerQ/Volo.Abp.BackgroundWorkers.TickerQ.csproj" />
</Folder>
<Folder Name="/test/">
<Project Path="test/AbpTestBase/AbpTestBase.csproj" />
Expand Down Expand Up @@ -252,4 +255,4 @@
<Project Path="test/Volo.Abp.Validation.Tests/Volo.Abp.Validation.Tests.csproj" />
<Project Path="test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj" />
</Folder>
</Solution>
</Solution>
3 changes: 3 additions & 0 deletions framework/src/Volo.Abp.BackgroundJobs.TickerQ/FodyWeavers.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>
30 changes: 30 additions & 0 deletions framework/src/Volo.Abp.BackgroundJobs.TickerQ/FodyWeavers.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
Loading
Loading