125 lines
4.3 KiB
C#
125 lines
4.3 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
public class PrinterQueue
|
|
{
|
|
public string PrinterIp { get; }
|
|
private readonly ConcurrentQueue<PrintJob> _queue;
|
|
private readonly ConcurrentStack<PrintJob> _priorityQueue; // For failed jobs
|
|
private readonly SemaphoreSlim _signal;
|
|
private readonly CancellationTokenSource _cancellationTokenSource;
|
|
private Task _processingTask;
|
|
private readonly IPrintService _printService;
|
|
private readonly ILogger _logger;
|
|
|
|
public bool IsProcessing { get; private set; }
|
|
public int QueueLength => _queue.Count + _priorityQueue.Count;
|
|
|
|
public PrinterQueue(string printerIp, IPrintService printService, ILogger logger)
|
|
{
|
|
PrinterIp = printerIp;
|
|
_queue = new ConcurrentQueue<PrintJob>();
|
|
_priorityQueue = new ConcurrentStack<PrintJob>();
|
|
_signal = new SemaphoreSlim(0);
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
_printService = printService;
|
|
_logger = logger;
|
|
}
|
|
|
|
public void Enqueue(PrintJob job)
|
|
{
|
|
_queue.Enqueue(job);
|
|
_signal.Release(); // Signal that there's work to do
|
|
_logger.LogInformation("Job {JobId} queued for printer {PrinterId}. Queue length: {QueueLength}", job.AreaId, PrinterIp, QueueLength);
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
if (_processingTask != null)
|
|
return;
|
|
|
|
IsProcessing = true;
|
|
_processingTask = Task.Run(() => ProcessQueueAsync(_cancellationTokenSource.Token));
|
|
_logger.LogInformation("Printer queue {PrinterId} started", PrinterIp);
|
|
}
|
|
private void EnqueuePriority(PrintJob job)
|
|
{
|
|
_priorityQueue.Push(job);
|
|
_signal.Release();
|
|
_logger.LogInformation("Job {JobId} priority queued for printer {PrinterId}. Queue length: {QueueLength}", job.AreaId, PrinterIp, QueueLength);
|
|
}
|
|
private async Task ProcessQueueAsync(CancellationToken cancellationToken)
|
|
{
|
|
while (!cancellationToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
// Wait for signal that there's work or cancellation
|
|
await _signal.WaitAsync(cancellationToken);
|
|
PrintJob job = null;
|
|
if (!_priorityQueue.TryPop(out job))
|
|
{
|
|
_queue.TryDequeue(out job);
|
|
}
|
|
|
|
if (job!=null)
|
|
{
|
|
_logger.LogInformation("Processing job {JobId} on printer {PrinterId}", job.AreaId, PrinterIp);
|
|
|
|
try
|
|
{
|
|
// Call the actual print function
|
|
bool success = await _printService.PrintAsync(PrinterIp, job);
|
|
|
|
if (!success)
|
|
{
|
|
// Re-queue with retry logic
|
|
job.RetryCount++;
|
|
_logger.LogWarning("Job {JobId} failed, retrying ({RetryCount}/3)", job.AreaId, job.RetryCount);
|
|
await Task.Delay(5000, cancellationToken); // Wait before retry
|
|
EnqueuePriority(job);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogInformation("Job {JobId} completed successfully on printer {PrinterId}", job.AreaId, PrinterIp);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error processing job {JobId}", job.AreaId);
|
|
// Handle exception (retry, log, etc.)
|
|
}
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
IsProcessing = false;
|
|
_logger.LogInformation("Printer queue {PrinterId} stopped", PrinterIp);
|
|
}
|
|
|
|
public async Task StopAsync()
|
|
{
|
|
_cancellationTokenSource.Cancel();
|
|
_signal.Release(); // Release to unblock the wait
|
|
|
|
if (_processingTask != null)
|
|
{
|
|
await _processingTask;
|
|
}
|
|
}
|
|
|
|
public List<PrintJob> GetPendingJobs()
|
|
{
|
|
return new List<PrintJob>(_queue);
|
|
}
|
|
}
|
|
|