Added BackgroundWorkers project.

pull/395/head
Halil ibrahim Kalkan 7 years ago
parent 8769aa08ac
commit 5021428119

@ -196,6 +196,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCor
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BackgroundJobs", "src\Volo.Abp.BackgroundJobs\Volo.Abp.BackgroundJobs.csproj", "{E6E0BBB5-48A7-4FDA-8A47-8B308BCD36AD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BackgroundWorkers", "src\Volo.Abp.BackgroundWorkers\Volo.Abp.BackgroundWorkers.csproj", "{6C3E76B8-C4DA-4E74-9F8B-A8BC4C831722}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -550,6 +552,10 @@ Global
{E6E0BBB5-48A7-4FDA-8A47-8B308BCD36AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6E0BBB5-48A7-4FDA-8A47-8B308BCD36AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6E0BBB5-48A7-4FDA-8A47-8B308BCD36AD}.Release|Any CPU.Build.0 = Release|Any CPU
{6C3E76B8-C4DA-4E74-9F8B-A8BC4C831722}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C3E76B8-C4DA-4E74-9F8B-A8BC4C831722}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C3E76B8-C4DA-4E74-9F8B-A8BC4C831722}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C3E76B8-C4DA-4E74-9F8B-A8BC4C831722}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -644,6 +650,7 @@ Global
{CAE68246-70A8-4E87-9B83-A9F7DA343E5E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{27C120C9-F618-4C1D-B959-8D0B048D0835} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{E6E0BBB5-48A7-4FDA-8A47-8B308BCD36AD} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{6C3E76B8-C4DA-4E74-9F8B-A8BC4C831722} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

@ -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…
Cancel
Save