mirror of https://github.com/abpframework/abp
parent
8769aa08ac
commit
5021428119
@ -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,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,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