Синглтонские зависимости в канале фоновой задачи / размещенная фоновая службаC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Синглтонские зависимости в канале фоновой задачи / размещенная фоновая служба

Сообщение Anonymous »

Я работаю над созданием некоторых конечных точек API API ASP.net Core 8.0 (в C#). Будет более 100 конечных точек в 40-50 репозиториях, которые являются частью той же экосистемы платформы; На данный момент это не вариант для реструктуризации коллекции. Существует также ряд задач, которые необходимо обработать асинхронно, не дожидаясь их выполнения перед отправкой ответа API. Цель состоит в том, чтобы установить его общим способом, где я могу создавать экземпляр службы и канала для каждого репо отдельно, функции Enqueue, которые содержат все фоновые задачи, и обрабатывать их в качестве службы.

Код: Выделить всё

IBackgroundTaskQueue
Интерфейс:

Код: Выделить всё

namespace My.Namespace.BackgroundTaskQueue
{
public interface IBackgroundTaskQueue
{
ValueTask QueueBackgroundWorkItemAsync(Func workItem);
ValueTask DequeueAsync(CancellationToken cancellationToken);
}
}
< /code>
BackgroundTaskQueue
реализация:

Код: Выделить всё

namespace My.Namespace.BackgroundTaskQueue
{
using System.Threading.Channels;

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private readonly Channel _queue;

public BackgroundTaskQueue(int capacity)
{
var options = new BoundedChannelOptions(capacity) {
FullMode = BoundedChannelFullMode.Wait
};

_queue = Channel.CreateBounded(options);
}

public async ValueTask QueueBackgroundWorkItemAsync(Func workItem)
{
if (workItem == null)
{
throw new ArgumentNullException(nameof(workItem));
}

await _queue.Writer.WriteAsync(workItem);
}

public async ValueTask DequeueAsync(CancellationToken cancellationToken)
{
var workItem = await _queue.Reader.ReadAsync(cancellationToken);

return workItem;
}
}
}
< /code>
BackgroundTaskQueueHostedService
:

Код: Выделить всё

namespace My.Namespace.BackgroundTaskQueue
{
using Microsoft.Extensions.Hosting;

public class BackgroundTaskQueueHostedService : BackgroundService
{
public IBackgroundTaskQueue TaskQueue { get; }

public BackgroundTaskQueueHostedService(IBackgroundTaskQueue taskQueue)
{
TaskQueue = taskQueue;
}

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)
{
// Error Handling
}
}
}

public override async Task StopAsync(CancellationToken stoppingToken)
{
await base.StopAsync(stoppingToken);
}
}
}
< /code>
The plan is to then instantiate this class / queue in startup.cs
, и мои контроллеры включают асинхронную функцию, которая содержит все задачи, которые я хочу обработать в фоновом режиме. Проблема заключается в том, что эти фоновые задачи полагаются на различные зависимости от обслуживания в одиночном возрасте, которые вводят в контроллеры. Но я не хочу вводить все синглтонские зависимости в фоновый сервис, поскольку цель состоит в том, чтобы иметь его достаточно общего для использования с любым из 40-50 репо, без создания специализированных реализаций класса фоновых услуг для каждого. < /P>

Код: Выделить всё

CustomControllerService
:

Код: Выделить всё

namespace My.Repo.Namespace.BL.ControllerServices.Custom
{
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using My.Namespace.BackgroundTaskQueue;
using My.Repo.Other.Namespace.Services;

public CustomControllerService : ICustomControllerService
{
private readonly IBackgroundTaskQueue _backgroundTaskQueue;
private readonly CancellationToken _ct;
private readonly IService1 _service1;
private readonly IService2 _service2;

public CustomControllerService(IBackgroundTaskQueue backgroundTaskQueue,
IHostApplicationLifetime applicationLifetime,
IService1 service1,
IService2 service2)
{
_backgroundTaskQueue = backgroundTaskQueue;
_ct = applicationLifetime.ApplicationStopping;
_service1 = service1;
_service2 = service2;
}

#region [Http Request Execution]

public async Task ProcessRequest(HttpRequest httpRequest)
{
ApiRequestContext apiRequestContext = new ApiRequestContext();
CustomRequestBody customRequestBody;

try
{
// Ingest the event and deserialize it to a data object dedicated to this endpoint
customRequestBody = await DeserializeRequestBody(httpRequest, apiRequestContext);

if (apiRequestContext?.ApiResponse?.HttpStatusCode == 200)
{
// Deserialization successful, process data
await ProcessRequestData(customRequestBody, apiRequestContext);
apiRequestContext.ApiResponse.Content = CreateResponseBody(apiRequestContext);
}
}
catch (Exception ex)
{
}
finally
{
}

// Return the current ApiResponse object contained in the ApiRequestContext
return apiRequestContext.ApiResponse;
}

#endregion

#region [Private Methods]

private async Task DeserializeRequestBody(HttpRequest httpRequest, ApiRequestContext apiRequestContext)
{
// Logic to deserialize request body into my custom object
return new CustomRequestBody;
}

private CustomResponseBody CreateResponseBody(ApiRequestContext apiRequestContext)
{
// Some logic to build API response
return new CustomResponseBody;
}

private async Task ProcessRequestData(CustomRequestBody customRequestBody, ApiRequestContext apiRequestContext)
{
try
{
await ProcessAwaitedTasks(customRequestBody, apiRequestContext);
await _backgroundTaskQueue.QueueBackgroundWorkItemAsync(
_ct =>  ProcessUnawaitedTasks(customRequestBody, _ct)
);
}
catch (Exception ex)
{
}
finally
{
}
}

private async Task ProcessAwaitedTasks(CustomRequestBody customRequestBody, ApiRequestContext apiRequestContext)
{
try
{
// Some synchronous sequence of async / await Tasks
}
catch (Exception e)
{
}
finally
{
}
}

private async ValueTask ProcessUnawaitedTasks(CustomRequestBody customRequestBody, CancellationToken ct)
{
try
{
// Some background async Tasks that I need executed, but not awaited for the api response
_ = _service1.Function1(customRequestBody);
_ = _service2.Function2(customRequestBody);
}
catch (Exception e)
{
}
finally
{
}
}

#endregion
}
}
< /code>
The controller service (simplified for brevity) will do some things to the incoming request, then proceed with processing the awaited tasks, followed by enqueueing an async function that contains some unawaited tasks into the BackgroundTaskQueue
(канал), прежде чем немедленно вернуть ответ API. Но эти неприемлемые задачи полагаются на зависимости в службе контроллера, таких как iService1 и iService2 . Я не хочу напрямую вводить эти зависимости в фоновый класс службы. В этой ситуации я видел обширную документацию о службах обселений, но я ничего не могу найти в управлении синглтонами. Спасибо!

Подробнее здесь: https://stackoverflow.com/questions/795 ... nd-service
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»