Переписать удаление служебной шины Azure

У меня есть класс ServiceBusBackgroundJobManager, он отправляет сообщения в служебную шину Azure.

public class ServiceBusBackgroundJobManager : BackgroundWorkerBase, IBackgroundJobManager
    {
        private readonly IAppConfigurationAccessor _configurationAccessor;
        private readonly ServiceBusClient _client;
        private ServiceBusSender _sender;
        private readonly string _serviceBusQueueName;

        public ServiceBusBackgroundJobManager(IAppConfigurationAccessor configurationAccessor)
        {
            _configurationAccessor = configurationAccessor;
            var connectionString = _configurationAccessor.Configuration["Abp:ServiceBusConnectionString"];
            _serviceBusQueueName = _configurationAccessor.Configuration["Abp:ServiceBusQueueName"];
            _client = new ServiceBusClient(connectionString);
        }

        public async Task<string> EnqueueAsync<TJob, TArgs>(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal,
            TimeSpan? delay = null) where TJob : IBackgroundJobBase<TArgs>
        {
            var messageBody = JsonSerializer.Serialize(args);
            var message = new ServiceBusMessage(Encoding.UTF8.GetBytes(messageBody))
            {
                MessageId = Guid.NewGuid().ToString(),
                ContentType = "application/json"
            };

            if (delay != null)
            {
                message.ScheduledEnqueueTime = DateTimeOffset.UtcNow.Add(delay.Value);
            }

            _sender = _client.CreateSender(_serviceBusQueueName);

            using var messageBatch = await _sender.CreateMessageBatchAsync();
            if (!messageBatch.TryAddMessage(message))
            {
                throw new Exception($"Exception");
            }

            try
            {
                await _sender.SendMessagesAsync(messageBatch);
            }
            finally
            {
                await _sender.DisposeAsync();
                await _client.DisposeAsync();
            }

            return string.Empty;
        }

    }
}

Проблема в том, что в блоке finally у меня есть dispose, но он не удаляется в 2-х вариантах

  • Таким образом, если два или более заданий будут поставлены в очередь, у второго не будет клиента, который можно было бы использовать.
  • Если в очереди нет заданий, клиент не удаляется.

Как мне нужно написать код, чтобы он работал в этих двух вариантах?

Вы создаете клиент в конструкторе, а это означает, что вы хотите удалить клиент только один раз, например, в методе Dispose работника. Если вы хотите каждый раз его удалять, вам придется каждый раз создавать клиент, то есть в самом методе EnqueueAsync.

huysentruitw 13.08.2024 09:24
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
50
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете рассмотреть возможность использования своих ресурсов вместе с блоками, как вы это делали для messageBatch.

Дополнительную информацию см. по этой ссылке: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using

ОП задал конкретный вопрос. Можете ли вы дать конкретный ответ на этот вопрос?

Enigmativity 13.08.2024 09:39

Я считаю, что ответ не может быть более конкретным, чем этот. Если вы уверены, что оно недостаточно конкретное, вы можете попытаться уточнить его. Спасибо @Enigmativity

Ozgur E. 13.08.2024 10:55

ОП спросил: «Итак, если два или более заданий будут поставлены в очередь, у второго не будет клиента для использования». и «Если в очереди нет заданий, клиент не удаляется». - Ваш ответ тоже не касается.

Enigmativity 14.08.2024 01:50

Приятель, судя по твоему последнему комментарию, ты знаешь ответ, мне просто интересно, почему бы тебе просто не ответить на вопрос, а не критиковать? @Энигмативность

Ozan BAYRAM 14.08.2024 10:05

Вам нужно каждый раз создавать отправителя? Безопасно кэшировать отправителя или использовать синглтон на протяжении всего времени существования приложения. https://learn.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.servicebussender?view=azure-dotnet

ОП задал конкретный вопрос. Можете ли вы дать конкретный ответ на этот вопрос?

Enigmativity 13.08.2024 09:39

Вы можете добиться этого более аккуратным способом, используя внедрение зависимостей (DI).

Существуют методы расширения DI, которые безопасно регистрируют классы служебной шины и гарантируют их удаление в нужное время, и вам не придется об этом беспокоиться. Вот как можно изменить код, чтобы сделать это.

1. Настройте DI

При запуске приложения (например, Program.cs) добавьте конфигурацию DI. Этот пример предназначен для функции Azure, но он будет аналогичен и в других платформах.

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication() // (Depending on your framework)
    .ConfigureServices(services =>
    {
        // Use the DI extension method for Azure clients.
        services.AddAzureClients(configureClients =>
        {
            // Add the ServiceBusClient.
            configureClients.AddServiceBusClient("YourConnectionString");

            // Add the Sender for your queue.
            configureClients.AddClient<ServiceBusSender, ServiceBusClientOptions>((_, _, provider) =>
                provider
                    .GetRequiredService<ServiceBusClient>()
                    .CreateSender("YourQueueName"));
        });

        // And then add your service classes, including your Manager class.
        services.AddScoped<IBackgroundJobManager, ServiceBusBackgroundJobManager>();

        // You should also add your other Service classes as DI.
    })
    .Build();

host.Run();

2. Упростите класс менеджера

Ваш класс Manager теперь может просто использовать экземпляры служебной шины в качестве зависимости конструктора, которую DI создаст соответствующим образом. Менеджер больше не несет ответственности за срок существования экземпляров, поэтому ему не нужно рассматривать возможность удаления.

public class ServiceBusBackgroundJobManager : BackgroundWorkerBase, IBackgroundJobManager
{
    private readonly ServiceBusSender _sender;

    public ServiceBusBackgroundJobManager(ServiceBusSender sender)
    {
        _sender = sender;
    }

    public async Task<string> EnqueueAsync<TJob, TArgs>(
        TArgs args,
        BackgroundJobPriority priority = BackgroundJobPriority.Normal,
        TimeSpan? delay = null) where TJob : IBackgroundJobBase<TArgs>
    {
        var messageBody = JsonSerializer.Serialize(args);
        var message = new ServiceBusMessage(Encoding.UTF8.GetBytes(messageBody))
        {
            MessageId = Guid.NewGuid().ToString(),
            ContentType = "application/json"
        };

        if (delay != null)
        {
            message.ScheduledEnqueueTime = DateTimeOffset.UtcNow.Add(delay.Value);
        }

        using var messageBatch = await _sender.CreateMessageBatchAsync();
        if (!messageBatch.TryAddMessage(message))
        {
            throw new Exception($"Exception");
        }

        await _sender.SendMessagesAsync(messageBatch);

        return string.Empty;
    }
}

Дальнейшее чтение

https://learn.microsoft.com/en-us/dotnet/api/overview/azure/messaging.servicebus-readme?view=azure-dotnet#client-lifetime

Другие вопросы по теме