运行两个相同后台服务.NET Core时网站超时问题

问题描述 投票:0回答:1

我正在运行两个相同的后台服务,它们唯一的工作就是从 azure sub 中拉取并发送到 API。我在下面粘贴另一个,仅更改

apiUrl
_topicName
_subscriptionName
的名称和值。

Startup.cs

services.AddHostedService<WhatsAppService>();
services.AddHostedService<CreateInvoiceService>(); // As soon as added the site starts
throwing timeout even though nothing is on azure sub.

服务等级:

public class WhatsAppService : BackgroundService
{
    private string _apiUrl = "";
    private readonly AzureServiceBusConnection _azureServiceBusConnection;
    private readonly WhatsAppSettings _whatsappsettings;
    private ServiceBusClient _client;
    private string _topicName = "";
    private string _subscriptionName = "";
    private readonly SemaphoreSlim _throttle;

    public WhatsAppService(IOptions<AzureServiceBusConnection> azureServiceBusConnection, IOptions<WhatsAppSettings> whatsappsettings)
    {
        _throttle = new SemaphoreSlim(10);  // Allows up to 10 concurrent requests

        _azureServiceBusConnection = azureServiceBusConnection.Value;
        _whatsappsettings = whatsappsettings.Value;

        _apiUrl = _whatsappsettings.ApiUrl;
        _topicName = _whatsappsettings.TopicName;
        _subscriptionName = _whatsappsettings.SubscriptionName;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _client = new ServiceBusClient(_azureServiceBusConnection.ConnectionString);
        var sessionTasks = new List<Task>(); // List to track session processing tasks

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                ServiceBusSessionReceiver sessionReceiver = null;

                try
                {
                    sessionReceiver = await _client.AcceptNextSessionAsync(_topicName, _subscriptionName);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error accepting session: {ex.Message}");
                    await Task.Delay(5000, stoppingToken); // Wait before retrying
                    continue; // Retry accepting the next session
                }

                if (sessionReceiver != null)
                {
                    // Start processing messages for this session in a new task
                    var task = Task.Run(async () =>
                    {
                        Console.WriteLine($"Processing messages for session: {sessionReceiver.SessionId}");

                        while (true)
                        {
                            ServiceBusReceivedMessage message = await sessionReceiver.ReceiveMessageAsync(TimeSpan.FromSeconds(10));

                            if (message == null)
                            {
                                Console.WriteLine("No more messages in this session.");
                                break; // Exit the inner loop if no more messages are available
                            }

                            var messageBody = Encoding.UTF8.GetString(message.Body);
                            Console.WriteLine($"Received message: {messageBody}");

                            var success = await SendDataToApiAsync(messageBody);
                            if (!success)
                            {
                                await sessionReceiver.AbandonMessageAsync(message);
                            }
                            else
                            {
                                await sessionReceiver.CompleteMessageAsync(message);
                            }
                        }

                        await sessionReceiver.CloseAsync();
                    });

                    sessionTasks.Add(task); // Track the task for this session
                }
                else
                {
                    Console.WriteLine("No sessions available to process.");
                }

                // Clean up completed tasks to avoid memory leaks
                sessionTasks.RemoveAll(t => t.IsCompleted);

                await Task.Delay(1000, stoppingToken); // Wait before checking for the next session
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error occurred: {ex.Message}");
            }
        }
    }

    private async Task<bool> SendDataToApiAsync(string message)
    {
        await _throttle.WaitAsync();  // Wait to enter the semaphore
        try
        {
            using var httpClient = new HttpClient();
            var content = new StringContent(message, Encoding.UTF8, "application/json");

            try
            {
                var response = await httpClient.PostAsync(_apiUrl, content);
                return response.IsSuccessStatusCode;
            }
            catch (HttpRequestException e)
            {
                Console.WriteLine($"HTTP Request failed: {e.Message}");
                return false;  // Log and handle HTTP request errors appropriately
            }
        }
        finally
        {
            _throttle.Release();  // Ensure semaphore is always released
        }
    }
}

这可能是什么原因,我知道我可以将它们两者合二为一,但又想知道当前流程或其资源是否有问题?

谢谢你

c# .net-core asp.net-core-hosted-services
1个回答
0
投票

听起来运行两个相同的后台服务会导致超时问题。您能否分享更多有关它们运行的环境以及任何特定错误日志的信息?您是否尝试过调试以查看是否存在瓶颈,例如连接限制或资源争用?如果与 API 响应时间或服务器资源相关,则检查断点或日志记录可以帮助缩小范围。

一个可能的问题可能是每个 BackgroundService 正在打开一个新的 ServiceBusClient 连接。不要使用单独的连接,而是尝试通过在 Startup.cs 中将其注册为单例来使用共享的 ServiceBusClientSemaphoreSlim(当前设置为 10)的高并发设置也可能会导致争用;减少这个数字或添加重试机制可能会有所帮助。此外,避免为每个请求重新创建 HttpClient,因为这可能会导致套接字耗尽——考虑将 HttpClient 设置为单例或使用 IHttpClientFactory。最后,检查服务器资源,如CPU和内存使用情况;运行两个服务可能会使环境超载。

如果有帮助请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.