QueueClient.OnMessage выдает StackOverflowException во время запуска рабочей роли

Я пытаюсь развернуть свою первую рабочую роль Azure, и я столкнулся с этой ошибкой, когда метод Run() вызывается во время запуска службы.

Произошло необработанное исключение типа «System.StackOverflowException» в неизвестном модуле.

Я попытался удаленно отладить свой код, и в этой строке выдается ошибка. MyPublisher похож на MyQueue, но в нем используется тема, а не очередь. Любая идея, почему QueueClient.OnMessage может вызвать StackOverflow?

Client.OnMessage (обработчик сообщений, параметры);

Вот частичный код. Мои извинения, если он не отформатирован правильно (попробую отформатировать) или чего-то не хватает в коде.

public class MyQueue
{
    String QueueName;
    public QueueClient Client { get; protected set; }

    public MyQueue(String queueName)
    {
        Trace.WriteLine($"Creating service Queue with name : {queueName} ");
        QueueName = queueName;
    }

    public void EstableshConnection(string connectionString = null)
    {
        Trace.WriteLine($"Establishing connection with service Queue : {QueueName} ");
        // Set the maximum number of concurrent connections 
        ServicePointManager.DefaultConnectionLimit = 12;

        connectionString = connectionString ?? CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");
        NamespaceManager namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
        if (!namespaceManager.QueueExists(QueueName))
            namespaceManager.CreateQueue(QueueName);

        Client = QueueClient.CreateFromConnectionString(connectionString, QueueName);
    }

    public void Send(BrokeredMessage message)
    {
        Trace.WriteLine($"Sending brokered message to queue : {QueueName} ");
        if (Client != null && !Client.IsClosed)
            Client.Send(message);
    }

    public void OnMessage(Action<BrokeredMessage> messageHandler)
    {
        Trace.WriteLine($"OnMessage handler: Queue Name : {QueueName} ");
        OnMessageOptions options = new OnMessageOptions();
        options.AutoComplete = true; // Indicates if the message-pump should call complete on messages after the callback has completed processing.
        options.MaxConcurrentCalls = 1; // Indicates the maximum number of concurrent calls to the callback the pump should initiate 
        options.ExceptionReceived += LogErrors; // Allows users to get notified of any errors encountered by the message pump

//=====================StackOverFlowException on Client.OnMessage======
        if (Client != null && !Client.IsClosed)
            Client.OnMessage(messageHandler, options);  //This is where I get StackOverflowException Error. 
    }

    private void LogErrors(object sender, ExceptionReceivedEventArgs e)
    {
        if (e.Exception != null)
            Trace.WriteLine("Queue client processing error: " + e.Exception.Message);
    }

    public void Disconnect()
    {
        Trace.WriteLine($"closing queue {QueueName}");
        Client.Close();
    }
}

Вот моя реализация рабочей роли.

public class MyWorkerRole : RoleEntryPoint
{
    #region Variables
    ManualResetEvent CompletedEvent = new ManualResetEvent(false);

    MyQueue RequestQueue;           //for Request
    MyPublisher ResponseTopicClient;    //ReponseTopic to notify Subscriber when processing is completed

    Public MyWorkerRole()
    {
        RequestQueue = new MyQueue("JobRequestQueue");
        ResponseTopicClient = new MyPublisher("JobCompletedTopic");
    }


    public override bool OnStart()
    {
        try
        {
            RequestQueue.EstableshConnection();
            ResponseTopicClient.EstableshConnection();
        }
        catch (Exception ex)
        {
            Trace.TraceWarning($"Trace: starting service failed. Error {ex.Message} ");
        }
        return base.OnStart();
    }

    public override void OnStop()
    {
        try
        {
            RequestQueue.Disconnect();
            ResponseTopicClient.Disconnect();
            CompletedEvent.Set();
        }
        catch (Exception ex)
        {
            Trace.TraceWarning($"Trace: stopping service failed with error. {ex.Message} ");
        }
        base.OnStop();
    }

    public override void Run()
    {
        try
        {
            Trace.WriteLine("Trace: Starting Message Processing");

            //var receivedMessage2 = RequestQueue.Client.Receive(new TimeSpan(hours: 0, minutes: 2, seconds: 0));
            RequestQueue.OnMessage((receivedMessage) =>
            {
                try
                {
                    Guid resultGuid = (Guid)receivedMessage.Properties["CorrelationGuid"];
                    Trace.TraceWarning($"Trace: processing message with GUID {resultGuid}");

                    var messageToSend = JobProcessor.ProcessRequest(receivedMessage);
                    if (messageToSend == null)
                    {
                        Trace.TraceError("Trace: > Broken message!");
                        receivedMessage.Abandon();
                        return;
                    }
                    ResponseTopicClient.Send(messageToSend);
                    receivedMessage.Complete();
                }
                catch (Exception ex)
                {
                    Trace.TraceError("Trace: Processing exception: " + ex.Message + "\nStack Trace" + ex.StackTrace);
                    Logger.Error("Processing exception: " + ex.Message + "\nStack Trace" + ex.StackTrace);
                }
            });
            CompletedEvent.WaitOne();
        }
        catch (Exception ex)
        {
            Trace.TraceError("Trace: Run exception: " + ex.Message + "\nStack Trace" + ex.StackTrace);
        }
        finally
        {
            CompletedEvent.Set();
        }
    }
}

person Patel    schedule 08.03.2018    source источник
comment
Спасибо. Я понимаю рекурсию, но я вызываю Client.OnMessage только один раз. Разве OnMessage просто не регистрирует действие, когда фактическое сообщение получено в очереди? Кроме того, данные диагностики не указывают на то, что делегат Action вызывается. В очередь пока ничего не отправляется, так как я буду отправлять запрос из отдельного приложения. Я могу попытаться удалить Topic из кода и посмотреть, решит ли это проблему, но я хочу понять, как это может повлиять на Queue.   -  person Patel    schedule 09.03.2018


Ответы (2)


Когда ваш работник запускается, он вызывает метод Run, и в вашем коде у вас есть:

 //var receivedMessage2 = RequestQueue.Client.Receive(new TimeSpan(hours: 0, minutes: 2, seconds: 0));

RequestQueue.OnMessage((receivedMessage) =>

Таким образом, код не ждет нового сообщения, потому что первая строка прокомментирована, и он вызывает метод OnMessage, который рекурсивно вызывает себя снова и снова, пока не будет запущен StackOverflowException.

Во всех случаях вам нужно изменить реализацию, потому что StackOverflowException все равно произойдет при получении нового сообщения.

person Haitham Shaddad    schedule 09.03.2018
comment
Хайтам Шаддад, спасибо за ответ. Я попытался упростить свой код для вызова QueueClient.Receive, и это дало мне ту же ошибку. Я также пытался использовать тот же код, предложенный @Abhishek Lal в этой ссылке, но это тоже не помогло. ‹br/› stackoverflow.com/questions/16714917/ /› Я думаю, что моя проблема в другом. - person Patel; 09.03.2018

Догадаться. Так что проблема была не в коде. Следующая ошибка была зарегистрирована в WADWindowsEventLogsTable под моей учетной записью хранения.

Имя неисправного приложения: WaWorkerHost.exe, версия: 2.7.1198.768, отметка времени: 0x57159090 Имя неисправного модуля: Microsoft.IntelliTrace.Profiler.SC.dll, версия: 15.0.27128.1, отметка времени: 0x5a1e2eb9 Код исключения: 0xc00000fd Смещение ошибки: 0x000008000000 Идентификатор сбойного процесса: 0xcf4 Время запуска сбойного приложения: 0x01d3b75ed89dc2f9 Путь сбойного приложения: F:\base\x64\WaWorkerHost.exe Путь сбойного модуля: F:\plugins\IntelliTrace\Runtime\x64\Microsoft.IntelliTrace.Profiler.SC.dll

Это дало мне подсказку об отключении IntelliTrace, и это сработало просто отлично. Вот как вы можете отключить при публикации пакета через VS 2017.

1.) Щелкните правой кнопкой мыши проект рабочей роли и выберите "Опубликовать" в меню
2.) На странице "Настройки" -> "Дополнительные настройки" снимите флажок "Включить IntelliTrace".

person Patel    schedule 09.03.2018