├── src
└── BackgroundTaskQueue
│ ├── BackgroundQueue
│ ├── ServiceCollectionExtensions.cs
│ ├── Generic
│ │ ├── ServiceCollectionExtensions.cs
│ │ ├── Models
│ │ │ ├── TicketBase.cs
│ │ │ ├── BaseTicket.cs
│ │ │ └── Ticket.cs
│ │ ├── BackgroundResultQueueService.cs
│ │ ├── BackgroundResultQueue.cs
│ │ └── IBackgroundResultQueue.cs
│ ├── Models
│ │ ├── BaseTicket.cs
│ │ └── Ticket.cs
│ ├── IBackgroundTaskQueue.cs
│ ├── BackgroundTaskQueue.cs
│ ├── BackgroundQueue.csproj
│ ├── BackgroundTaskQueueService.cs
│ └── BackgroundQueue.xml
│ └── BackgroundQueue.sln
├── LICENSE
├── README.md
└── .gitignore
/src/BackgroundTaskQueue/BackgroundQueue/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace BackgroundQueue
4 | {
5 | public static partial class ServiceCollectionExtensions
6 | {
7 | ///
8 | /// Adds the required BackgroundTaskQueue services.
9 | ///
10 | public static IServiceCollection AddBackgroundTaskQueue(this IServiceCollection services) =>
11 | services
12 | .AddSingleton()
13 | .AddHostedService();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/Generic/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 |
3 | namespace BackgroundQueue.Generic
4 | {
5 | public static partial class ServiceCollectionExtensions
6 | {
7 | ///
8 | /// Adds the required BackgroundResultQueue services.
9 | ///
10 | public static IServiceCollection AddBackgroundResultQueue(
11 | this IServiceCollection services
12 | ) =>
13 | services
14 | .AddSingleton()
15 | .AddHostedService();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/Models/BaseTicket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace BackgroundQueue.Models
6 | {
7 | internal class BaseTicket : Ticket
8 | {
9 | private readonly Func _task;
10 | private readonly Action _exception;
11 |
12 | internal BaseTicket(Func task, Action exception)
13 | {
14 | _task = task;
15 | _exception = exception;
16 | }
17 |
18 | public override Task ExecuteAsync(CancellationToken ct) => _task(ct);
19 |
20 | public override void OnException(Exception ex) => _exception(ex);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/Generic/Models/TicketBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace BackgroundQueue.Generic.Models
6 | {
7 | ///
8 | /// This class is only for internal use.
9 | ///
10 | public abstract class TicketBase
11 | {
12 | ///
13 | /// Gets called when the gets enqueued.
14 | ///
15 | public virtual void Enqueued() { }
16 |
17 | ///
18 | /// Gets called when the method errors out.
19 | ///
20 | public virtual void OnException(Exception ex) { }
21 |
22 | internal abstract Task ProccessAsync(CancellationToken ct);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/Models/Ticket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace BackgroundQueue.Models
6 | {
7 | ///
8 | /// Inherit from this class, if you want to create a new Ticket, which should get enqueued in a BackgroundTaskQueue.
9 | ///
10 | public abstract class Ticket
11 | {
12 | ///
13 | /// Gets called when the gets enqueued.
14 | ///
15 | public virtual void Enqueued() { }
16 |
17 | ///
18 | /// Gets called when the method errors out.
19 | ///
20 | public virtual void OnException(Exception ex) { }
21 |
22 | ///
23 | /// Contains the core logic of the Ticket.
24 | ///
25 | public abstract Task ExecuteAsync(CancellationToken ct);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Twenty
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29411.138
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BackgroundQueue", "BackgroundQueue\BackgroundQueue.csproj", "{5864A1EB-DFEF-40A6-BDFE-4C8C536736DC}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {5864A1EB-DFEF-40A6-BDFE-4C8C536736DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {5864A1EB-DFEF-40A6-BDFE-4C8C536736DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {5864A1EB-DFEF-40A6-BDFE-4C8C536736DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {5864A1EB-DFEF-40A6-BDFE-4C8C536736DC}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {8B58955E-8F70-4F4C-9E34-BC5DD1DCD43F}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/Generic/Models/BaseTicket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace BackgroundQueue.Generic.Models
6 | {
7 | internal class BaseTicket : Ticket
8 | {
9 | private readonly Func _task;
10 | private readonly Action _exception;
11 |
12 | internal BaseTicket(Func task, Action exception)
13 | {
14 | _task = task;
15 | _exception = exception;
16 | }
17 |
18 | public override Task ExecuteAsync(CancellationToken ct) => _task(ct);
19 |
20 | public override void OnException(Exception ex) => _exception(ex);
21 | }
22 |
23 | internal class BaseTicket : Ticket
24 | {
25 | private readonly Func> _task;
26 | private readonly Action _exception;
27 |
28 | internal BaseTicket(Func> task, Action exception)
29 | {
30 | _task = task;
31 | _exception = exception;
32 | }
33 |
34 | public override Task ExecuteAsync(CancellationToken ct) => _task(ct);
35 |
36 | public override void OnException(Exception ex) => _exception(ex);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/IBackgroundTaskQueue.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using BackgroundQueue.Models;
5 |
6 | namespace BackgroundQueue
7 | {
8 | public interface IBackgroundTaskQueue : IDisposable
9 | {
10 | ///
11 | /// Adds a new to the Queue, which will get processed in a background thread. This method will return immediately.
12 | ///
13 | /// The Task which will get enqueued.
14 | void Enqueue(Func task);
15 |
16 | ///
17 | /// Adds a new to the Queue, which will get processed in a background thread. This method will return immediately.
18 | ///
19 | /// The Task which will get enqueued.
20 | /// A action which will get called, if the task fails.
21 | void Enqueue(Func task, Action exception);
22 |
23 | ///
24 | /// Adds a new to the Queue, which will get processed in a background thread. This method will return immediately.
25 | ///
26 | /// The ticket which will get enqueued.
27 | void Enqueue(Ticket ticket);
28 |
29 | ///
30 | /// Dequeues a from the .
31 | ///
32 | /// Returns the enqueued .
33 | Task DequeueAsync(CancellationToken ct);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/BackgroundTaskQueue.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using BackgroundQueue.Models;
6 |
7 | namespace BackgroundQueue
8 | {
9 | public class BackgroundTaskQueue : IBackgroundTaskQueue
10 | {
11 | public bool IsDisposed { get; private set; }
12 | private readonly ConcurrentQueue _taskQueue;
13 | private readonly SemaphoreSlim _signal;
14 |
15 | public BackgroundTaskQueue()
16 | {
17 | _taskQueue = new ConcurrentQueue();
18 | _signal = new SemaphoreSlim(0);
19 | }
20 |
21 | ///
22 | public void Enqueue(Func task) => Enqueue(task, exception => { });
23 |
24 | ///
25 | public void Enqueue(Func task, Action exception)
26 | {
27 | Enqueue(new BaseTicket(task, exception));
28 | }
29 |
30 | ///
31 | public void Enqueue(Ticket ticket)
32 | {
33 | _taskQueue.Enqueue(ticket);
34 | _signal.Release();
35 | ticket.Enqueued();
36 | }
37 |
38 | ///
39 | public async Task DequeueAsync(CancellationToken ct)
40 | {
41 | await _signal.WaitAsync(ct);
42 | _taskQueue.TryDequeue(out var ticket);
43 |
44 | return ticket;
45 | }
46 |
47 | public void Dispose()
48 | {
49 | if (!IsDisposed)
50 | {
51 | _signal.Dispose();
52 | IsDisposed = true;
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/BackgroundQueue.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1;netstandard2.0;netcoreapp3.1;net6.0
5 | preview
6 | enable
7 | 1.0.0.3
8 | Twenty
9 | Twenty
10 | BackgroundQueue
11 | BackgroundQueue is a simple way to queue background Tasks in ASP.Net Core and in .Net in general.
12 | Twenty
13 | https://github.com/TwentyFourMinutes/BackgroundQueue
14 | true
15 | true
16 | LICENSE
17 | queue background backgroundqueue aspnetcore aspnet
18 | Copyright ©2022 Twenty
19 | BackgroundQueue
20 |
21 |
22 |
23 | BackgroundQueue.xml
24 |
25 |
26 |
27 |
28 | all
29 | runtime; build; native; contentfiles; analyzers; buildtransitive
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | True
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/BackgroundTaskQueueService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Hosting;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace BackgroundQueue
8 | {
9 | public class BackgroundTaskQueueService : BackgroundService
10 | {
11 | public IBackgroundTaskQueue TaskQueue { get; }
12 | private readonly ILogger _logger;
13 |
14 | public BackgroundTaskQueueService(
15 | ILogger logger,
16 | IBackgroundTaskQueue taskQueue
17 | )
18 | {
19 | _logger = logger;
20 | TaskQueue = taskQueue;
21 | }
22 |
23 | public override Task StartAsync(CancellationToken ct)
24 | {
25 | _logger.LogInformation(
26 | $"Background Service {nameof(BackgroundTaskQueueService)} is starting..."
27 | );
28 |
29 | return base.StartAsync(ct);
30 | }
31 |
32 | protected override async Task ExecuteAsync(CancellationToken ct)
33 | {
34 | _logger.LogInformation(
35 | $"Background Service {nameof(BackgroundTaskQueueService)} is running."
36 | );
37 |
38 | while (!ct.IsCancellationRequested)
39 | {
40 | var ticket = await TaskQueue.DequeueAsync(ct);
41 |
42 | try
43 | {
44 | await ticket.ExecuteAsync(ct);
45 | }
46 | catch (Exception ex)
47 | {
48 | ticket.OnException(ex);
49 | _logger.LogError(ex, $"Error occurred while executing {nameof(ticket)}.");
50 | }
51 | }
52 | }
53 |
54 | public override Task StopAsync(CancellationToken ct)
55 | {
56 | _logger.LogInformation(
57 | $"Background Service {nameof(BackgroundTaskQueueService)} is stopping..."
58 | );
59 |
60 | return base.StopAsync(ct);
61 | }
62 |
63 | public override void Dispose()
64 | {
65 | TaskQueue.Dispose();
66 | base.Dispose();
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/Generic/BackgroundResultQueueService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Hosting;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace BackgroundQueue.Generic
8 | {
9 | public class BackgroundResultQueueService : BackgroundService
10 | {
11 | public IBackgroundResultQueue ResultQueue { get; }
12 | private readonly ILogger _logger;
13 |
14 | public BackgroundResultQueueService(
15 | ILogger logger,
16 | IBackgroundResultQueue taskQueue
17 | )
18 | {
19 | _logger = logger;
20 | ResultQueue = taskQueue;
21 | }
22 |
23 | public override Task StartAsync(CancellationToken ct)
24 | {
25 | _logger.LogInformation(
26 | $"Background Service {nameof(BackgroundResultQueueService)} is starting..."
27 | );
28 |
29 | return base.StartAsync(ct);
30 | }
31 |
32 | protected override async Task ExecuteAsync(CancellationToken ct)
33 | {
34 | _logger.LogInformation(
35 | $"Background Service {nameof(BackgroundResultQueueService)} is running."
36 | );
37 |
38 | while (!ct.IsCancellationRequested)
39 | {
40 | var ticket = await ResultQueue.DequeueAsync(ct);
41 |
42 | try
43 | {
44 | await ticket.ProccessAsync(ct);
45 | }
46 | catch (Exception ex)
47 | {
48 | ticket.OnException(ex);
49 | _logger.LogError(ex, $"Error occurred while executing {nameof(ticket)}.");
50 | }
51 | }
52 | }
53 |
54 | public override Task StopAsync(CancellationToken ct)
55 | {
56 | _logger.LogInformation(
57 | $"Background Service {nameof(BackgroundResultQueueService)} is stopping..."
58 | );
59 |
60 | return base.StopAsync(ct);
61 | }
62 |
63 | public override void Dispose()
64 | {
65 | ResultQueue.Dispose();
66 | base.Dispose();
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/BackgroundTaskQueue/BackgroundQueue/Generic/Models/Ticket.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 |
4 | namespace BackgroundQueue.Generic.Models
5 | {
6 | ///
7 | /// Inherit from this class, if you want to create a new Ticket, which should get enqueued in a BackgroundResultQueue.
8 | ///
9 | public abstract class Ticket : TicketBase
10 | {
11 | private readonly TaskCompletionSource