diff --git a/Extensions/BackgroundServiceExtensions.cs b/Extensions/BackgroundServiceExtensions.cs
new file mode 100644
index 0000000..c716fb5
--- /dev/null
+++ b/Extensions/BackgroundServiceExtensions.cs
@@ -0,0 +1,25 @@
+using Microsoft.Extensions.DependencyInjection;
+using xCommons.Providers;
+
+namespace xCommons.Extensions
+{
+ public static class BackgroundServiceExtensions
+ {
+ ///
+ /// Register Background Services ...
+ ///
+ ///
+ ///
+ ///
+ public static void AddXBackgroundService(
+ this IServiceCollection source,
+ TService service
+ )
+ where TService : XBackgroundService
+ {
+ //
+ source.AddSingleton(service);
+ source.AddHostedService();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Providers/XBackgroundService.cs b/Providers/XBackgroundService.cs
new file mode 100644
index 0000000..d8e35b7
--- /dev/null
+++ b/Providers/XBackgroundService.cs
@@ -0,0 +1,26 @@
+using System;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace xCommons.Providers
+{
+ ///
+ /// Default Background Service ...
+ ///
+ public abstract class XBackgroundService : BackgroundService
+ {
+ //
+ protected readonly IServiceProvider serviceProvider;
+ protected readonly ILogger logger;
+
+ protected XBackgroundService(
+ IServiceProvider serviceProvider,
+ ILogger logger
+ )
+ {
+ //
+ this.logger = logger;
+ this.serviceProvider = serviceProvider;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Providers/XResumableBackgroundService.cs b/Providers/XResumableBackgroundService.cs
new file mode 100644
index 0000000..3d6bc45
--- /dev/null
+++ b/Providers/XResumableBackgroundService.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace xCommons.Providers
+{
+ ///
+ /// Resumable Background Task ...
+ ///
+ public abstract class XResumableBackgroundService : XBackgroundService
+ {
+ ///
+ /// Check is Paused ...
+ ///
+ protected bool paused = false;
+
+ protected XResumableBackgroundService(
+ IServiceProvider serviceProvider,
+ ILogger logger
+ ) : base(
+ logger: logger,
+ serviceProvider: serviceProvider
+ )
+ { }
+
+ protected override async Task ExecuteAsync(
+ CancellationToken stoppingToken = default
+ )
+ {
+ //
+ if (paused)
+ {
+ return;
+ }
+
+ //
+ await DoWorkAsync(
+ payload: null,
+ cancellationToken: stoppingToken
+ );
+ }
+
+ ///
+ /// do all required works here ...
+ ///
+ ///
+ ///
+ ///
+ public abstract Task DoWorkAsync(
+ object payload = null,
+ CancellationToken cancellationToken = default
+ );
+
+ ///
+ /// Pause Consuming ...
+ ///
+ ///
+ public bool Pause()
+ {
+ //
+ var result = !paused;
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ paused = true;
+ result = paused;
+ return result;
+ }
+
+ ///
+ /// Resume Consuming ...
+ ///
+ ///
+ public bool Resume()
+ {
+ //
+ var result = paused;
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ paused = false;
+ result = !paused;
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Providers/XTimeBasedBackgroundService.cs b/Providers/XTimeBasedBackgroundService.cs
new file mode 100644
index 0000000..2527cbc
--- /dev/null
+++ b/Providers/XTimeBasedBackgroundService.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using xCommons.Extensions;
+using xExceptions.Constants;
+
+namespace xCommons.Providers
+{
+ ///
+ /// Do Background Jobs based on Time Intervals ...
+ ///
+ public abstract class XTimeBasedBackgroundService : XBackgroundService
+ {
+ //
+ private bool isWorking = false;
+ private readonly TimeSpan restartInterval;
+ private readonly SemaphoreSlim mlock = new(1, 1);
+ public DateTime? LastRunTime { get; private set; }
+ private CancellationTokenSource cancellationTokenSource;
+
+ protected XTimeBasedBackgroundService(
+ IServiceProvider serviceProvider,
+ ILogger logger,
+ int intervalInMinutes = 10
+ ) : base(
+ logger: logger,
+ serviceProvider: serviceProvider
+ )
+ {
+ //
+ // Validate Interval ...
+ if (intervalInMinutes <= 0)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ restartInterval = TimeSpan.FromMinutes(intervalInMinutes);
+ }
+
+ ///
+ /// Override base action to Implement timing ...
+ ///
+ ///
+ ///
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ //
+ while (!stoppingToken.IsCancellationRequested)
+ {
+ try
+ {
+ if (!isWorking)
+ {
+ //
+ // Enable Working ...
+ await mlock.WaitAsync(stoppingToken);
+ try
+ {
+ isWorking = true;
+ }
+ finally
+ {
+ mlock.Release();
+ }
+
+ //
+ // Start a new work task ...
+ cancellationTokenSource = CancellationTokenSource
+ .CreateLinkedTokenSource(stoppingToken);
+
+ //
+ // Execute the work ...
+ await ExecuteWorkAsync(cancellationTokenSource.Token);
+
+ //
+ // Disable Working ...
+ await mlock.WaitAsync(stoppingToken);
+ try
+ {
+ isWorking = false;
+ }
+ finally
+ {
+ mlock.Release();
+ }
+
+ //
+ // Wait for the restart interval ...
+ await Task.Delay(restartInterval, stoppingToken);
+ }
+ else
+ {
+ //
+ // Prevent tight error loops ...
+ await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ //
+ // Disable Working ...
+ await mlock.WaitAsync(stoppingToken);
+ try
+ {
+ isWorking = false;
+ }
+ finally
+ {
+ mlock.Release();
+ }
+ break;
+ }
+ catch (Exception)
+ {
+ //
+ // Disable Working ...
+ await mlock.WaitAsync(stoppingToken);
+ try
+ {
+ isWorking = false;
+ }
+ finally
+ {
+ mlock.Release();
+ }
+
+ //
+ // Prevent tight error loops ...
+ await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
+ }
+ }
+ }
+
+ ///
+ /// Override Stop Background Worker ...
+ ///
+ ///
+ ///
+ public override async Task StopAsync(CancellationToken cancellationToken)
+ {
+ //
+ // Cancel the current work session
+ cancellationTokenSource.Cancel();
+ await base.StopAsync(cancellationToken);
+ }
+
+ ///
+ /// Dispose all Objects ...
+ ///
+ public override void Dispose()
+ {
+ mlock.Dispose();
+ cancellationTokenSource.Dispose();
+ GC.SuppressFinalize(this);
+ base.Dispose();
+ }
+
+ ///
+ /// do all required works here ...
+ ///
+ ///
+ ///
+ public abstract Task DoWorkAsync(
+ CancellationToken cancellationToken = default
+ );
+
+ ///
+ /// Refresh Worker ...
+ ///
+ ///
+ ///
+ public async Task Refresh(
+ CancellationToken cancellationToken = default
+ )
+ {
+ //
+ // Cancel current work if running
+ cancellationTokenSource.Cancel();
+
+ //
+ // Wait a moment for cancellation
+ await Task.Delay(100, cancellationToken);
+
+ //
+ // Start new work immediately
+ cancellationTokenSource = CancellationTokenSource
+ .CreateLinkedTokenSource(cancellationToken);
+ await ExecuteWorkAsync(cancellationTokenSource.Token);
+ }
+
+ //
+ #region Private ...
+ private async Task ExecuteWorkAsync(CancellationToken cancellationToken)
+ {
+ //
+ LastRunTime = DateTime.UtcNow;
+ try
+ {
+ await DoWorkAsync(cancellationToken);
+ }
+ catch (OperationCanceledException)
+ {
+ }
+ catch (Exception)
+ {
+ }
+ finally
+ {
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file