Browse Source

Add TickerQ background worker integration

Co-authored-by: hikalkan <1210527+hikalkan@users.noreply.github.com>
pull/23802/head
copilot-swe-agent[bot] 1 year ago
parent
commit
bdcc69755c
  1. 5
      docs/en/framework/infrastructure/background-workers/index.md
  2. 211
      docs/en/framework/infrastructure/background-workers/tickerq.md
  3. 3
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/FodyWeavers.xml
  4. 30
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/FodyWeavers.xsd
  5. 25
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo.Abp.BackgroundWorkers.TickerQ.csproj
  6. 31
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkerTickerQOptions.cs
  7. 37
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs
  8. 44
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/ITickerQBackgroundWorker.cs
  9. 46
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQBackgroundWorkerBase.cs
  10. 131
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQBackgroundWorkerManager.cs
  11. 128
      framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQPeriodicBackgroundWorkerAdapter.cs

5
docs/en/framework/infrastructure/background-workers/index.md

@ -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
@ -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

211
docs/en/framework/infrastructure/background-workers/tickerq.md

@ -0,0 +1,211 @@
# TickerQ Background Worker Manager
[TickerQ](https://github.com/dotnetdevelopersdz/TickerQ) 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 Framework to use it instead of the [default background worker manager](../background-workers).
The major advantages of TickerQ include:
- **Performance**: Reflection-free design with source generators for optimal performance
- **EF Core Integration**: Native support for Entity Framework Core for job persistence
- **Flexible Scheduling**: Support for both cron expressions and time-based execution
- **Real-time Dashboard**: Built-in dashboard for monitoring and managing background jobs
- **Modern .NET**: Built for modern .NET with async/await support throughout
## 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
````
### Manual Installation
If you want to manually install:
1. Add the [Volo.Abp.BackgroundWorkers.TickerQ](https://www.nuget.org/packages/Volo.Abp.BackgroundWorkers.TickerQ) NuGet package to your project:
````
dotnet add package Volo.Abp.BackgroundWorkers.TickerQ
````
2. Add the `AbpBackgroundWorkersTickerQModule` to the dependency list of your module:
````csharp
[DependsOn(
//...other dependencies
typeof(AbpBackgroundWorkersTickerQModule) //Add the new module dependency
)]
public class YourModule : AbpModule
{
}
````
> TickerQ background worker integration provides an adapter `TickerQPeriodicBackgroundWorkerAdapter` to automatically load any `PeriodicBackgroundWorkerBase` and `AsyncPeriodicBackgroundWorkerBase` derived classes as `ITickerQBackgroundWorker` instances. This allows you to easily switch over to use TickerQ as the background manager even if you have existing background workers that are based on the [default background workers implementation](../background-workers).
## Configuration
You need to configure TickerQ with your preferred storage provider. TickerQ supports various storage options including Entity Framework Core.
1. First, configure TickerQ in your module's `ConfigureServices` method:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment();
//... other configurations.
ConfigureTickerQ(context, configuration);
}
private void ConfigureTickerQ(ServiceConfigurationContext context, IConfiguration configuration)
{
// TODO: Configure TickerQ here when the package becomes available
// This would typically involve setting up the database connection,
// configuring the scheduler options, and setting up the dashboard
}
````
2. You can configure the ABP TickerQ integration options:
````csharp
Configure<AbpBackgroundWorkerTickerQOptions>(options =>
{
options.IsAutoRegisterEnabled = true; // Auto-register TickerQ workers
options.DefaultCronExpression = "0 * * ? * *"; // Default: every minute
options.DefaultMaxRetryAttempts = 3; // Default retry attempts
options.DefaultPriority = 0; // Default priority
});
````
## Create a Background Worker
`TickerQBackgroundWorkerBase` is an easy way to create a background worker.
````csharp
public class MyLogWorker : TickerQBackgroundWorkerBase
{
public MyLogWorker()
{
JobId = nameof(MyLogWorker);
CronExpression = "0 */10 * ? * *"; // Every 10 minutes
Priority = 1; // Higher priority
MaxRetryAttempts = 5; // Retry up to 5 times on failure
}
public override Task DoWorkAsync(CancellationToken cancellationToken = default)
{
Logger.LogInformation("Executed MyLogWorker with TickerQ!");
return Task.CompletedTask;
}
}
````
### Properties
* **JobId** - A unique identifier for the job (optional, defaults to the class name)
* **CronExpression** - A CRON expression for scheduling (see [CRON expression](https://en.wikipedia.org/wiki/Cron#CRON_expression))
* **Priority** - Job priority (higher values = higher priority, default is 0)
* **MaxRetryAttempts** - Maximum number of retry attempts on failure (default is 3)
* **AutoRegister** - Whether to automatically register this worker (default is true)
> You can directly implement the `ITickerQBackgroundWorker` interface, but `TickerQBackgroundWorkerBase` provides useful properties like Logger and service access.
## Register Background Workers
TickerQ background workers are automatically registered if `AutoRegister` is `true` (default). However, you can also manually register them:
````csharp
[DependsOn(typeof(AbpBackgroundWorkersTickerQModule))]
public class MyModule : AbpModule
{
public override async Task OnApplicationInitializationAsync(
ApplicationInitializationContext context)
{
await context.AddBackgroundWorkerAsync<MyLogWorker>();
}
}
````
## Migrating from Other Background Worker Implementations
TickerQ integration provides adapters for existing background workers:
### From Default Background Workers
Existing `AsyncPeriodicBackgroundWorkerBase` and `PeriodicBackgroundWorkerBase` workers will automatically work with TickerQ through the adapter system. The adapter will convert timer periods to appropriate cron expressions.
### From Quartz or Hangfire
When migrating from Quartz or Hangfire, you can:
1. Keep existing workers unchanged (they'll work through adapters)
2. Gradually migrate to `TickerQBackgroundWorkerBase` for better performance and features
3. Use the native TickerQ features like source generator optimizations
## Dashboard Integration
TickerQ provides a real-time dashboard for monitoring background jobs. To enable the dashboard:
````csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
// ... others
// TODO: Add TickerQ dashboard integration when available
// app.UseTickerQDashboard("/tickerq");
app.UseConfiguredEndpoints();
}
````
## Advanced Features
### Source Generator Optimizations
TickerQ uses source generators to eliminate reflection and improve performance. When using TickerQ-specific features, your jobs will benefit from:
- Compile-time job registration
- Zero-allocation job execution
- Optimized serialization
### EF Core Integration
TickerQ provides native Entity Framework Core integration for job persistence:
````csharp
public class MyEfCoreWorker : TickerQBackgroundWorkerBase
{
private readonly IRepository<MyEntity> _repository;
public MyEfCoreWorker(IRepository<MyEntity> repository)
{
_repository = repository;
JobId = nameof(MyEfCoreWorker);
CronExpression = "0 0 2 ? * *"; // Daily at 2 AM
}
public override async Task DoWorkAsync(CancellationToken cancellationToken = default)
{
// Work with EF Core entities
var entities = await _repository.GetListAsync(cancellationToken: cancellationToken);
// Process entities...
Logger.LogInformation("Processed {Count} entities", entities.Count);
}
}
````
## See Also
* [Background Workers](../background-workers)
* [Background Jobs](../background-jobs)
* [Quartz Background Worker Manager](./quartz.md)
* [Hangfire Background Worker Manager](./hangfire.md)

3
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/FodyWeavers.xsd

@ -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>

25
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo.Abp.BackgroundWorkers.TickerQ.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.BackgroundWorkers.TickerQ</AssemblyName>
<PackageId>Volo.Abp.BackgroundWorkers.TickerQ</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.BackgroundWorkers\Volo.Abp.BackgroundWorkers.csproj" />
<!-- Note: This would need to reference the actual TickerQ package when it becomes available -->
<!-- <PackageReference Include="TickerQ" Version="*" /> -->
</ItemGroup>
</Project>

31
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkerTickerQOptions.cs

@ -0,0 +1,31 @@
namespace Volo.Abp.BackgroundWorkers.TickerQ;
/// <summary>
/// Options for TickerQ background workers.
/// </summary>
public class AbpBackgroundWorkerTickerQOptions
{
/// <summary>
/// Gets or sets whether automatic registration is enabled for TickerQ workers.
/// Default is true.
/// </summary>
public bool IsAutoRegisterEnabled { get; set; } = true;
/// <summary>
/// Gets or sets the default cron expression for workers that don't specify one.
/// Default is every minute: "0 * * ? * *"
/// </summary>
public string DefaultCronExpression { get; set; } = "0 * * ? * *";
/// <summary>
/// Gets or sets the default maximum retry attempts.
/// Default is 3.
/// </summary>
public int DefaultMaxRetryAttempts { get; set; } = 3;
/// <summary>
/// Gets or sets the default priority for workers.
/// Default is 0 (normal priority).
/// </summary>
public int DefaultPriority { get; set; } = 0;
}

37
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpBackgroundWorkersTickerQModule.cs

@ -0,0 +1,37 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Modularity;
namespace Volo.Abp.BackgroundWorkers.TickerQ;
/// <summary>
/// ABP module for TickerQ background workers integration.
/// TickerQ 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.
/// </summary>
[DependsOn(
typeof(AbpBackgroundWorkersModule))]
public class AbpBackgroundWorkersTickerQModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Register TickerQ-specific services
// The TickerQBackgroundWorkerManager will automatically replace the default manager
// due to the [Dependency(ReplaceServices = true)] attribute
}
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
{
// Check if background workers are enabled
var options = context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundWorkerOptions>>().Value;
if (!options.IsEnabled)
{
// If background workers are disabled, we don't need to initialize TickerQ
return;
}
// Initialize TickerQ background worker manager
var tickerQManager = context.ServiceProvider.GetRequiredService<TickerQBackgroundWorkerManager>();
tickerQManager.Initialize();
}
}

44
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/ITickerQBackgroundWorker.cs

@ -0,0 +1,44 @@
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundWorkers.TickerQ;
/// <summary>
/// Interface for TickerQ background workers.
/// TickerQ is a fast, reflection-free background task scheduler for .NET.
/// </summary>
public interface ITickerQBackgroundWorker : IBackgroundWorker
{
/// <summary>
/// Gets or sets the cron expression for the job scheduling.
/// </summary>
string? CronExpression { get; set; }
/// <summary>
/// Gets or sets the job identifier.
/// </summary>
string? JobId { get; set; }
/// <summary>
/// Gets or sets whether to automatically register this worker.
/// Default is true.
/// </summary>
bool AutoRegister { get; set; }
/// <summary>
/// Gets or sets the job priority.
/// </summary>
int Priority { get; set; }
/// <summary>
/// Gets or sets the maximum retry attempts for failed jobs.
/// </summary>
int MaxRetryAttempts { get; set; }
/// <summary>
/// The main work execution method.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the work execution.</returns>
Task DoWorkAsync(CancellationToken cancellationToken = default);
}

46
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQBackgroundWorkerBase.cs

@ -0,0 +1,46 @@
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundWorkers.TickerQ;
/// <summary>
/// Base class for TickerQ background workers.
/// TickerQ is a fast, reflection-free background task scheduler for .NET.
/// </summary>
public abstract class TickerQBackgroundWorkerBase : BackgroundWorkerBase, ITickerQBackgroundWorker
{
/// <summary>
/// Gets or sets the cron expression for the job scheduling.
/// </summary>
public string? CronExpression { get; set; }
/// <summary>
/// Gets or sets the job identifier.
/// </summary>
public string? JobId { get; set; }
/// <summary>
/// Gets or sets whether to automatically register this worker.
/// Default is true.
/// </summary>
public bool AutoRegister { get; set; } = true;
/// <summary>
/// Gets or sets the job priority.
/// Default is 0 (normal priority).
/// </summary>
public int Priority { get; set; } = 0;
/// <summary>
/// Gets or sets the maximum retry attempts for failed jobs.
/// Default is 3.
/// </summary>
public int MaxRetryAttempts { get; set; } = 3;
/// <summary>
/// The main work execution method that must be implemented by derived classes.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the work execution.</returns>
public abstract Task DoWorkAsync(CancellationToken cancellationToken = default);
}

131
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQBackgroundWorkerManager.cs

@ -0,0 +1,131 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
namespace Volo.Abp.BackgroundWorkers.TickerQ;
/// <summary>
/// TickerQ implementation of the background worker manager.
/// Replaces the default background worker manager when TickerQ integration is enabled.
/// </summary>
[Dependency(ReplaceServices = true)]
public class TickerQBackgroundWorkerManager : BackgroundWorkerManager, ISingletonDependency
{
private readonly AbpBackgroundWorkerTickerQOptions _options;
private readonly IServiceProvider _serviceProvider;
private bool _isInitialized;
public TickerQBackgroundWorkerManager(
IOptions<AbpBackgroundWorkerTickerQOptions> options,
IServiceProvider serviceProvider)
{
_options = options.Value;
_serviceProvider = serviceProvider;
}
public override async Task StartAsync(CancellationToken cancellationToken = default)
{
Logger.LogInformation("Starting TickerQ Background Worker Manager...");
if (!_isInitialized)
{
await InitializeAsync();
}
await base.StartAsync(cancellationToken);
Logger.LogInformation("TickerQ Background Worker Manager started.");
}
public override async Task StopAsync(CancellationToken cancellationToken = default)
{
Logger.LogInformation("Stopping TickerQ Background Worker Manager...");
await base.StopAsync(cancellationToken);
Logger.LogInformation("TickerQ Background Worker Manager stopped.");
}
public override async Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default)
{
if (worker is ITickerQBackgroundWorker tickerQWorker)
{
await ScheduleTickerQJobAsync(tickerQWorker, cancellationToken);
}
else
{
// For non-TickerQ workers, use the default behavior
await base.AddAsync(worker, cancellationToken);
}
}
protected virtual async Task InitializeAsync()
{
Logger.LogDebug("Initializing TickerQ Background Worker Manager...");
// TODO: Initialize TickerQ scheduler here when the actual TickerQ library is available
// This would involve setting up the TickerQ configuration, database connections, etc.
_isInitialized = true;
Logger.LogDebug("TickerQ Background Worker Manager initialized.");
await Task.CompletedTask;
}
protected virtual async Task ScheduleTickerQJobAsync(ITickerQBackgroundWorker worker, CancellationToken cancellationToken = default)
{
Logger.LogInformation("Scheduling TickerQ job: {JobId}", worker.JobId ?? worker.GetType().Name);
try
{
// TODO: Implement actual TickerQ job scheduling when the library is available
// This would involve:
// 1. Creating a TickerQ job definition
// 2. Setting up the cron expression or time-based trigger
// 3. Configuring retry policy and priority
// 4. Registering the job with TickerQ scheduler
// For now, we'll just log the configuration
Logger.LogDebug("TickerQ job configuration: JobId={JobId}, CronExpression={CronExpression}, Priority={Priority}, MaxRetryAttempts={MaxRetryAttempts}",
worker.JobId ?? worker.GetType().Name,
worker.CronExpression ?? _options.DefaultCronExpression,
worker.Priority,
worker.MaxRetryAttempts);
await Task.CompletedTask;
}
catch (Exception ex)
{
Logger.LogError(ex, "Failed to schedule TickerQ job: {JobId}", worker.JobId ?? worker.GetType().Name);
throw;
}
}
public void Initialize()
{
// Automatically register TickerQ background workers if auto-registration is enabled
if (!_options.IsAutoRegisterEnabled)
{
return;
}
Logger.LogDebug("Auto-registering TickerQ background workers...");
var backgroundWorkers = _serviceProvider.GetServices<IBackgroundWorker>();
foreach (var backgroundWorker in backgroundWorkers)
{
if (backgroundWorker is ITickerQBackgroundWorker tickerQWorker && tickerQWorker.AutoRegister)
{
AddAsync(tickerQWorker).ConfigureAwait(false).GetAwaiter().GetResult();
}
}
Logger.LogDebug("Auto-registration of TickerQ background workers completed.");
}
}

128
framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/TickerQPeriodicBackgroundWorkerAdapter.cs

@ -0,0 +1,128 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundWorkers.TickerQ;
/// <summary>
/// Adapter to enable existing periodic background workers to work with TickerQ.
/// This allows users to migrate from the default background worker implementation to TickerQ
/// without changing their existing worker code.
/// </summary>
public class TickerQPeriodicBackgroundWorkerAdapter<TWorker> : TickerQBackgroundWorkerBase, ITransientDependency
where TWorker : class, IBackgroundWorker
{
private readonly IServiceProvider _serviceProvider;
public TickerQPeriodicBackgroundWorkerAdapter(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
// Set default job ID based on the worker type
JobId = typeof(TWorker).Name;
}
public override async Task DoWorkAsync(CancellationToken cancellationToken = default)
{
Logger.LogDebug("Executing adapted periodic worker: {WorkerType}", typeof(TWorker).Name);
using var scope = _serviceProvider.CreateScope();
var worker = scope.ServiceProvider.GetRequiredService<TWorker>();
try
{
if (worker is IPeriodicBackgroundWorker periodicWorker)
{
await periodicWorker.DoWorkAsync(cancellationToken);
}
else if (worker is AsyncPeriodicBackgroundWorkerBase asyncPeriodicWorker)
{
await asyncPeriodicWorker.DoWorkAsync(cancellationToken);
}
else if (worker is PeriodicBackgroundWorkerBase syncPeriodicWorker)
{
syncPeriodicWorker.DoWork();
await Task.CompletedTask;
}
else
{
Logger.LogWarning("Worker {WorkerType} is not a supported periodic worker type", typeof(TWorker).Name);
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Error executing adapted periodic worker: {WorkerType}", typeof(TWorker).Name);
throw;
}
}
/// <summary>
/// Configures the adapter based on the original worker's settings.
/// </summary>
public virtual TickerQPeriodicBackgroundWorkerAdapter<TWorker> Configure(TWorker originalWorker)
{
// Try to extract timing information from the original worker
if (originalWorker is AsyncPeriodicBackgroundWorkerBase asyncWorker)
{
// Convert timer period to cron expression (approximate)
if (asyncWorker.Timer?.Period != null)
{
var periodMinutes = asyncWorker.Timer.Period / 60000; // Convert ms to minutes
if (periodMinutes < 1)
{
CronExpression = "*/30 * * ? * *"; // Every 30 seconds for very short periods
}
else if (periodMinutes == 1)
{
CronExpression = "0 * * ? * *"; // Every minute
}
else if (periodMinutes < 60)
{
CronExpression = $"0 */{periodMinutes} * ? * *"; // Every N minutes
}
else
{
var hours = periodMinutes / 60;
CronExpression = $"0 0 */{hours} ? * *"; // Every N hours
}
}
// Use cron expression if available
if (!string.IsNullOrEmpty(asyncWorker.CronExpression))
{
CronExpression = asyncWorker.CronExpression;
}
}
else if (originalWorker is PeriodicBackgroundWorkerBase syncWorker)
{
// Similar logic for sync workers
if (syncWorker.Timer?.Period != null)
{
var periodMinutes = syncWorker.Timer.Period / 60000;
if (periodMinutes < 1)
{
CronExpression = "*/30 * * ? * *";
}
else if (periodMinutes == 1)
{
CronExpression = "0 * * ? * *";
}
else if (periodMinutes < 60)
{
CronExpression = $"0 */{periodMinutes} * ? * *";
}
else
{
var hours = periodMinutes / 60;
CronExpression = $"0 0 */{hours} ? * *";
}
}
}
return this;
}
}
Loading…
Cancel
Save