mirror of
https://github.com/Theodor-Springmann-Stiftung/hamann-ausgabe-core.git
synced 2025-10-29 17:25:32 +00:00
139 lines
4.4 KiB
C#
139 lines
4.4 KiB
C#
namespace HaWeb.BackgroundTask;
|
|
|
|
using System.Threading.Channels;
|
|
|
|
public interface IBackgroundTaskQueue {
|
|
ValueTask QueueBackgroundWorkItemAsync(Func<CancellationToken, ValueTask> workItem);
|
|
ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(CancellationToken cancellationToken);
|
|
}
|
|
|
|
public interface IMonitorLoop {
|
|
public void StartMonitorLoop();
|
|
}
|
|
|
|
public class BackgroundTaskQueue : IBackgroundTaskQueue {
|
|
private readonly Channel<Func<CancellationToken, ValueTask>> _queue;
|
|
|
|
public BackgroundTaskQueue(int capacity) {
|
|
var options = new BoundedChannelOptions(capacity) {
|
|
FullMode = BoundedChannelFullMode.Wait
|
|
};
|
|
_queue = Channel.CreateBounded<Func<CancellationToken, ValueTask>>(options);
|
|
}
|
|
|
|
public async ValueTask QueueBackgroundWorkItemAsync(Func<CancellationToken, ValueTask> workItem) {
|
|
if (workItem == null) {
|
|
throw new ArgumentNullException(nameof(workItem));
|
|
}
|
|
await _queue.Writer.WriteAsync(workItem);
|
|
}
|
|
|
|
public async ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
|
|
CancellationToken cancellationToken
|
|
) {
|
|
var workItem = await _queue.Reader.ReadAsync(cancellationToken);
|
|
return workItem;
|
|
}
|
|
}
|
|
|
|
public class QueuedHostedService : BackgroundService {
|
|
private readonly ILogger<QueuedHostedService> _logger;
|
|
public IBackgroundTaskQueue TaskQueue { get; }
|
|
|
|
public QueuedHostedService(IBackgroundTaskQueue taskQueue, ILogger<QueuedHostedService> logger) {
|
|
TaskQueue = taskQueue;
|
|
_logger = logger;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
|
|
await BackgroundProcessing(stoppingToken);
|
|
}
|
|
|
|
private async Task BackgroundProcessing(CancellationToken stoppingToken) {
|
|
while (!stoppingToken.IsCancellationRequested) {
|
|
var workItem = await TaskQueue.DequeueAsync(stoppingToken);
|
|
|
|
try {
|
|
await workItem(stoppingToken);
|
|
}
|
|
catch (Exception ex) {
|
|
_logger.LogError(ex, "Error occurred executing {WorkItem}.", nameof(workItem));
|
|
}
|
|
}
|
|
}
|
|
|
|
public override async Task StopAsync(CancellationToken stoppingToken) {
|
|
_logger.LogInformation("Queued Hosted Service is stopping.");
|
|
|
|
await base.StopAsync(stoppingToken);
|
|
}
|
|
}
|
|
|
|
public class MonitorLoop : IMonitorLoop {
|
|
private readonly IBackgroundTaskQueue _taskQueue;
|
|
private readonly ILogger _logger;
|
|
private readonly CancellationToken _cancellationToken;
|
|
|
|
public MonitorLoop(
|
|
IBackgroundTaskQueue taskQueue,
|
|
ILogger<MonitorLoop> logger,
|
|
IHostApplicationLifetime applicationLifetime
|
|
) {
|
|
_taskQueue = taskQueue;
|
|
_logger = logger;
|
|
_cancellationToken = applicationLifetime.ApplicationStopping;
|
|
}
|
|
|
|
public void StartMonitorLoop() {
|
|
_logger.LogInformation("MonitorAsync Loop is starting.");
|
|
|
|
// Run a console user input loop in a background thread
|
|
Task.Run(async () => await MonitorAsync());
|
|
}
|
|
|
|
private async ValueTask MonitorAsync() {
|
|
while (!_cancellationToken.IsCancellationRequested) {
|
|
var keyStroke = Console.ReadKey();
|
|
|
|
if (keyStroke.Key == ConsoleKey.W) {
|
|
// Enqueue a background work item
|
|
await _taskQueue.QueueBackgroundWorkItemAsync(BuildWorkItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async ValueTask BuildWorkItem(CancellationToken token) {
|
|
// Simulate three 5-second tasks to complete
|
|
// for each enqueued work item
|
|
|
|
int delayLoop = 0;
|
|
var guid = Guid.NewGuid().ToString();
|
|
|
|
_logger.LogInformation("Queued Background Task {Guid} is starting.", guid);
|
|
|
|
while (!token.IsCancellationRequested && delayLoop < 3) {
|
|
try {
|
|
await Task.Delay(TimeSpan.FromSeconds(5), token);
|
|
}
|
|
catch (OperationCanceledException) {
|
|
// Prevent throwing if the Delay is cancelled
|
|
}
|
|
|
|
delayLoop++;
|
|
|
|
_logger.LogInformation(
|
|
"Queued Background Task {Guid} is running. " + "{DelayLoop}/3",
|
|
guid,
|
|
delayLoop
|
|
);
|
|
}
|
|
|
|
if (delayLoop == 3) {
|
|
_logger.LogInformation("Queued Background Task {Guid} is complete.", guid);
|
|
}
|
|
else {
|
|
_logger.LogInformation("Queued Background Task {Guid} was cancelled.", guid);
|
|
}
|
|
}
|
|
}
|