Библиотека шарписта | C#, F#, .NET, ASP.NET
22.5K subscribers
2.48K photos
39 videos
85 files
4.7K links
Все самое полезное для C#-разработчика в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/b60af5a4

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Download Telegram
👨‍💻 Worker Services и Channels вместо сторонних библиотек

Каждый разработчик сталкивался с необходимостью выполнять долгие операции в фоне: отправка писем, обработка платежей, генерация отчётов, синхронизация данных.

Обычно первая мысль — взять Hangfire, Quartz или Azure Functions. Но .NET 9 предоставляет встроенные примитивы, которые отлично справляются с этой задачей самостоятельно.

Традиционные подходы — блокирующая коллекция и самописные очереди имеют недостатки: требуют ручной синхронизации, рискуют блокировкой потоков, не имеют встроенной поддержки обратного давления.

Реализуем очередь задач с помощью каналов и фоновые сервисы

Интерфейс и реализация очереди:
public interface IBackgroundTaskQueue
{
ValueTask QueueAsync(Func<CancellationToken, Task> workItem);
ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
}

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, Task>> _queue;

public BackgroundTaskQueue(int capacity = 100)
{
var options = new BoundedChannelOptions(capacity)
{
SingleReader = false,
SingleWriter = false,
FullMode = BoundedChannelFullMode.Wait
};
_queue = Channel.CreateBounded<Func<CancellationToken, Task>>(options);
}

public async ValueTask QueueAsync(Func<CancellationToken, Task> workItem)
=> await _queue.Writer.WriteAsync(workItem);

public async ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken)
=> await _queue.Reader.ReadAsync(cancellationToken);
}


Фоновые сервисы для обработки:
public class BackgroundWorker : BackgroundService
{
private readonly IBackgroundTaskQueue _taskQueue;
private readonly ILogger<BackgroundWorker> _logger;

public BackgroundWorker(IBackgroundTaskQueue taskQueue, ILogger<BackgroundWorker> logger)
{
_taskQueue = taskQueue;
_logger = logger;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Фоновый worker запущен");

while (!stoppingToken.IsCancellationRequested)
{
var workItem = await _taskQueue.DequeueAsync(stoppingToken);
try
{
await workItem(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при выполнении задачи");
}
}

_logger.LogInformation("Worker останавливается...");
}
}


Использование в контроллере:
app.MapPost("/send-email", async (IBackgroundTaskQueue queue) =>
{
await queue.QueueAsync(async token =>
{
await Task.Delay(1000, token); // имитация отправки
Console.WriteLine($"Email отправлен в {DateTime.UtcNow}");
});
return Results.Accepted();
});


Запрос возвращается немедленно, а работа продолжается в фоне. Queue автоматически буферизирует задачи, управляет нагрузкой и применяет обратное давление, если очередь переполнится.

Когда использовать этот подход

Подходит:

• Внутренняя обработка задач в приложении
• Нет нужды в UI-панели мониторинга
• Self-contained сервисы

Возьмите библиотеку, если:

• Нужна распределённая обработка
• Требуется веб-интерфейс для управления
• Задачи должны пережить перезагрузку приложения

➡️ Источник

🐸 Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17