Files
Print_server/Inspectron.Epson/Queue/PrinterQueue.cs
2026-01-13 09:06:47 +01:00

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);
}
}