mirror of https://github.com/abpframework/abp.git
12 changed files with 463 additions and 0 deletions
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.BackgroundWorkers</AssemblyName> |
|||
<PackageId>Volo.Abp.BackgroundWorkers</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.Threading\Volo.Abp.Threading.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,17 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BackgroundWorkers |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpThreadingModule) |
|||
)] |
|||
public class AbpBackgroundWorkersModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddAssemblyOf<AbpBackgroundWorkersModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BackgroundWorkers |
|||
{ |
|||
/// <summary>
|
|||
/// Base class that can be used to implement <see cref="IBackgroundWorker"/>.
|
|||
/// </summary>
|
|||
public abstract class BackgroundWorkerBase : RunnableBase, IBackgroundWorker |
|||
{ |
|||
//TODO: Add UOW, Localization and other useful properties..?
|
|||
|
|||
public ILogger<BackgroundWorkerBase> Logger { protected get; set; } |
|||
|
|||
protected BackgroundWorkerBase() |
|||
{ |
|||
Logger = NullLogger<BackgroundWorkerBase>.Instance; |
|||
} |
|||
|
|||
public override void Start() |
|||
{ |
|||
Logger.LogDebug("Starting background worker: " + ToString()); |
|||
base.Start(); |
|||
Logger.LogDebug("Started background worker: " + ToString()); |
|||
} |
|||
|
|||
public override void Stop() |
|||
{ |
|||
Logger.LogDebug("Stopping background worker: " + ToString()); |
|||
base.Stop(); |
|||
Logger.LogDebug("Stopped background worker: " + ToString()); |
|||
} |
|||
|
|||
public override void WaitToStop() |
|||
{ |
|||
Logger.LogDebug("Waiting background worker to completely stop: " + ToString()); |
|||
base.WaitToStop(); |
|||
Logger.LogDebug("Background worker is completely stopped: " + ToString()); |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return GetType().FullName; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BackgroundWorkers |
|||
{ |
|||
/// <summary>
|
|||
/// Implements <see cref="IBackgroundWorkerManager"/>.
|
|||
/// </summary>
|
|||
public class BackgroundWorkerManager : RunnableBase, IBackgroundWorkerManager, ISingletonDependency, IDisposable |
|||
{ |
|||
private readonly List<IBackgroundWorker> _backgroundJobs; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BackgroundWorkerManager"/> class.
|
|||
/// </summary>
|
|||
public BackgroundWorkerManager() |
|||
{ |
|||
_backgroundJobs = new List<IBackgroundWorker>(); |
|||
} |
|||
|
|||
public override void Start() |
|||
{ |
|||
base.Start(); |
|||
|
|||
_backgroundJobs.ForEach(job => job.Start()); |
|||
} |
|||
|
|||
public override void Stop() |
|||
{ |
|||
_backgroundJobs.ForEach(job => job.Stop()); |
|||
|
|||
base.Stop(); |
|||
} |
|||
|
|||
public override void WaitToStop() |
|||
{ |
|||
_backgroundJobs.ForEach(job => job.WaitToStop()); |
|||
|
|||
base.WaitToStop(); |
|||
} |
|||
|
|||
public void Add(IBackgroundWorker worker) |
|||
{ |
|||
_backgroundJobs.Add(worker); |
|||
|
|||
if (IsRunning) |
|||
{ |
|||
worker.Start(); |
|||
} |
|||
} |
|||
|
|||
private bool _isDisposed; |
|||
|
|||
public void Dispose() |
|||
{ |
|||
if (_isDisposed) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
_isDisposed = true; |
|||
|
|||
//TODO: ???
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BackgroundWorkers |
|||
{ |
|||
/// <summary>
|
|||
/// Interface for a worker (thread) that runs on background to perform some tasks.
|
|||
/// </summary>
|
|||
public interface IBackgroundWorker : IRunnable |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BackgroundWorkers |
|||
{ |
|||
/// <summary>
|
|||
/// Used to manage background workers.
|
|||
/// </summary>
|
|||
public interface IBackgroundWorkerManager : IRunnable |
|||
{ |
|||
/// <summary>
|
|||
/// Adds a new worker. Starts the worker immediately if <see cref="IBackgroundWorkerManager"/> has started.
|
|||
/// </summary>
|
|||
/// <param name="worker">
|
|||
/// The worker. It should be resolved from IOC.
|
|||
/// </param>
|
|||
void Add(IBackgroundWorker worker); |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
using System; |
|||
using Microsoft.Extensions.Logging; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.BackgroundWorkers |
|||
{ |
|||
/// <summary>
|
|||
/// Extends <see cref="BackgroundWorkerBase"/> to add a periodic running Timer.
|
|||
/// </summary>
|
|||
public abstract class PeriodicBackgroundWorkerBase : BackgroundWorkerBase |
|||
{ |
|||
protected readonly AbpTimer Timer; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PeriodicBackgroundWorkerBase"/> class.
|
|||
/// </summary>
|
|||
/// <param name="timer">A timer.</param>
|
|||
protected PeriodicBackgroundWorkerBase(AbpTimer timer) |
|||
{ |
|||
Timer = timer; |
|||
Timer.Elapsed += Timer_Elapsed; |
|||
} |
|||
|
|||
public override void Start() |
|||
{ |
|||
base.Start(); |
|||
Timer.Start(); |
|||
} |
|||
|
|||
public override void Stop() |
|||
{ |
|||
Timer.Stop(); |
|||
base.Stop(); |
|||
} |
|||
|
|||
public override void WaitToStop() |
|||
{ |
|||
Timer.WaitToStop(); |
|||
base.WaitToStop(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Handles the Elapsed event of the Timer.
|
|||
/// </summary>
|
|||
private void Timer_Elapsed(object sender, System.EventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
DoWork(); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Logger.LogException(ex); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Periodic works should be done by implementing this method.
|
|||
/// </summary>
|
|||
protected abstract void DoWork(); |
|||
} |
|||
} |
|||
@ -0,0 +1,141 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Threading |
|||
{ |
|||
/// <summary>
|
|||
/// A roboust timer implementation that ensures no overlapping occurs. It waits exactly specified <see cref="Period"/> between ticks.
|
|||
/// </summary>
|
|||
public class AbpTimer : RunnableBase, ITransientDependency |
|||
{ |
|||
/// <summary>
|
|||
/// This event is raised periodically according to Period of Timer.
|
|||
/// </summary>
|
|||
public event EventHandler Elapsed; |
|||
|
|||
/// <summary>
|
|||
/// Task period of timer (as milliseconds).
|
|||
/// </summary>
|
|||
public int Period { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Indicates whether timer raises Elapsed event on Start method of Timer for once.
|
|||
/// Default: False.
|
|||
/// </summary>
|
|||
public bool RunOnStart { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// This timer is used to perfom the task at spesified intervals.
|
|||
/// </summary>
|
|||
private readonly Timer _taskTimer; |
|||
|
|||
/// <summary>
|
|||
/// Indicates that whether timer is running or stopped.
|
|||
/// </summary>
|
|||
private volatile bool _running; |
|||
|
|||
/// <summary>
|
|||
/// Indicates that whether performing the task or _taskTimer is in sleep mode.
|
|||
/// This field is used to wait executing tasks when stopping Timer.
|
|||
/// </summary>
|
|||
private volatile bool _performingTasks; |
|||
|
|||
/// <summary>
|
|||
/// Creates a new Timer.
|
|||
/// </summary>
|
|||
public AbpTimer() |
|||
{ |
|||
_taskTimer = new Timer(TimerCallBack, null, Timeout.Infinite, Timeout.Infinite); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Starts the timer.
|
|||
/// </summary>
|
|||
public override void Start() |
|||
{ |
|||
if (Period <= 0) |
|||
{ |
|||
throw new AbpException("Period should be set before starting the timer!"); |
|||
} |
|||
|
|||
base.Start(); |
|||
|
|||
_running = true; |
|||
_taskTimer.Change(RunOnStart ? 0 : Period, Timeout.Infinite); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Stops the timer.
|
|||
/// </summary>
|
|||
public override void Stop() |
|||
{ |
|||
lock (_taskTimer) |
|||
{ |
|||
_running = false; |
|||
_taskTimer.Change(Timeout.Infinite, Timeout.Infinite); |
|||
} |
|||
|
|||
base.Stop(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Waits the service to stop.
|
|||
/// </summary>
|
|||
public override void WaitToStop() |
|||
{ |
|||
lock (_taskTimer) |
|||
{ |
|||
while (_performingTasks) |
|||
{ |
|||
Monitor.Wait(_taskTimer); |
|||
} |
|||
} |
|||
|
|||
base.WaitToStop(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This method is called by _taskTimer.
|
|||
/// </summary>
|
|||
/// <param name="state">Not used argument</param>
|
|||
private void TimerCallBack(object state) |
|||
{ |
|||
lock (_taskTimer) |
|||
{ |
|||
if (!_running || _performingTasks) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
_taskTimer.Change(Timeout.Infinite, Timeout.Infinite); |
|||
_performingTasks = true; |
|||
} |
|||
|
|||
try |
|||
{ |
|||
if (Elapsed != null) |
|||
{ |
|||
Elapsed(this, new EventArgs()); |
|||
} |
|||
} |
|||
catch |
|||
{ |
|||
|
|||
} |
|||
finally |
|||
{ |
|||
lock (_taskTimer) |
|||
{ |
|||
_performingTasks = false; |
|||
if (_running) |
|||
{ |
|||
_taskTimer.Change(Period, Timeout.Infinite); |
|||
} |
|||
|
|||
Monitor.Pulse(_taskTimer); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
namespace Volo.Abp.Threading |
|||
{ |
|||
/// <summary>
|
|||
/// Interface to start/stop self threaded services.
|
|||
/// </summary>
|
|||
public interface IRunnable |
|||
{ |
|||
/// <summary>
|
|||
/// Starts the service.
|
|||
/// </summary>
|
|||
void Start(); |
|||
|
|||
/// <summary>
|
|||
/// Sends stop command to the service.
|
|||
/// Service may return immediately and stop asynchronously.
|
|||
/// A client should then call <see cref="WaitToStop"/> method to ensure it's stopped.
|
|||
/// </summary>
|
|||
void Stop(); |
|||
|
|||
/// <summary>
|
|||
/// Waits the service to stop.
|
|||
/// </summary>
|
|||
void WaitToStop(); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
namespace Volo.Abp.Threading |
|||
{ |
|||
/// <summary>
|
|||
/// Base implementation of <see cref="IRunnable"/>.
|
|||
/// </summary>
|
|||
public abstract class RunnableBase : IRunnable |
|||
{ |
|||
/// <summary>
|
|||
/// A boolean value to check if this is running.
|
|||
/// </summary>
|
|||
public bool IsRunning => _isRunning; |
|||
private volatile bool _isRunning; |
|||
|
|||
public virtual void Start() |
|||
{ |
|||
_isRunning = true; |
|||
} |
|||
|
|||
public virtual void Stop() |
|||
{ |
|||
_isRunning = false; |
|||
} |
|||
|
|||
public virtual void WaitToStop() |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
namespace Volo.Abp.Threading |
|||
{ |
|||
/// <summary>
|
|||
/// Some extension methods for <see cref="IRunnable"/>.
|
|||
/// </summary>
|
|||
public static class RunnableExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Calls <see cref="IRunnable.Stop"/> and then <see cref="IRunnable.WaitToStop"/>.
|
|||
/// </summary>
|
|||
public static void StopAndWaitToStop(this IRunnable runnable) |
|||
{ |
|||
runnable.Stop(); |
|||
runnable.WaitToStop(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue