Как определить, почему SignalR в Microsoft.Owin возвращает HTTP 500? - PullRequest
0 голосов
/ 30 марта 2020

Мы создали инфраструктуру для наших фоновых демонов, чтобы помочь им вести себя согласованно, и поэтому нам не нужно постоянно переписывать один и тот же код.

И, конечно, десять лет спустя мы создали новое.

Одним из приложений в старой структуре является приложение сигнализации SignalR. Он размещает экземпляр SignalR в Microsoft Owin, а затем периодически проверяет базу данных на наличие всего необходимого для pu sh, затем обращается к веб-сайту SignalR, который затем использует настроенную объединительную панель для связи с другими запущенными веб-серверами, что затем отправим sh различным веб-клиентам.

Вроде запутанно, но это работает.

И теперь моя работа - переместить его в новую среду фонового приложения, и я ' я получаю ошибки HTTP 500 при попытке запустить веб-приложение.

Код в новом демоне почти такой же, как и в старом приложении, и я не могу понять, почему он работает в этом и не в другом.

Способ работы обеих сред состоит в том, что у каждого демона есть функция doWork (), которая вызывается неоднократно. В старом приложении была занята / wait l oop, которая вызывала бы doWork (). В новом приложении doWork () вызывается из System.Timers.Timer ElapsedEventHandler.

Мы определили класс для переноса экземпляра SignalR:

public class SignalRWebApp : IDisposable
{
    public readonly string signalRUrl;
    private IDisposable webApp;

    public SignalRWebApp()
    {
        this.signalRUrl = String.Format("http://localhost:{0}", getFreePort());
        this.webApp = null;
    }

    private static int getFreePort()
    {
        var listener = new TcpListener(IPAddress.Loopback, 0);
        listener.Start();
        var port = ((IPEndPoint) listener.LocalEndpoint).Port;
        listener.Stop();
        return port;
    }

    public bool started { get { return this.webApp != null; } }
    public void start(string signalRBackplaneConnectionString)
    {
        if (this.webApp != null)
            return;

        Action<IAppBuilder> startAction = app =>
        {
            app.UseCors(CorsOptions.AllowAll);
            GlobalHost.DependencyResolver.UseSqlServer(signalRBackplaneConnectionString);
            app.MapSignalR();
        };

        this.webApp = WebApp.Start(this.signalRUrl, startAction);
    }

    #region IDisposable
    [...]
    #endregion
}

Мы храним экземпляр этого в элементе stati c, так что функция work () может получить к нему доступ:

public class Utils
{
    public static SignalRWebApp signalRWebApp;
}

И затем мы заключаем наш код запуска в использование (), чтобы он существовал, пока приложение работает. Обратите внимание - если вы посмотрите на класс SignalRWebApp выше, вы заметите, что он на самом деле ничего не делает, пока не запустится.

using (Utils.signalRWebApp = new SignalRWebApp())
{
    // initialize and run the background app
    // (this will repeatedly call work() until shutdown is requested)
}

Затем наша рабочая функция запускается запуском SignalRWebApp, если она еще не запущен:

public class JobLockDaemon
{
    private string signalRUrl;
    private IHubProxy ticketLockSignalRHubProxy;
    private HubConnection signalRConnection;

    public JobLockDaemon()
    {
        this.checkedSnapshot = false;
        this.signalRUrl = null;
        this.ticketLockSignalRHubProxy = null;
        this.signalRConnection = null;
    }

    public void doWork()
    {
        this.connectToSignalR();

        // go ahead and do something
    }

    private void connectToSignalR()
    {
        if (this.signalRUrl == null)
        {
            if (!Utils.signalRWebApp.started)
            {
                Utils.signalRWebApp
                    .start(this.signalRBackplaneConnectionString());
            }

            this.signalRUrl = Utils.signalRWebApp.signalRUrl;
        }

        if (this.ticketLockSignalRHubProxy == null)
        {
            this.signalRConnection = new HubConnection(this.signalRUrl);
            this.ticketLockSignalRHubProxy = this.signalRConnection.CreateHubProxy("TicketLockSignalRHub");

            this.signalRConnection.Start().Wait();
        }
    }
}

И все работает, в старой платформе Daemon. Но в новом я получаю исключение this.signalRConnection.Start ():

System.AggregateException
Message    "One or more errors occurred."    string
InnerException    {
    "StatusCode: 500,
    ReasonPhrase: 'Internal Server Error',
    Version: 1.1,
    Content: System.Net.Http.StreamContent,
    Headers:
    {
        Date: Mon, 30 Mar 2020 16:29:27 GMT
        Server: Microsoft-HTTPAPI/2.0
        Content-Length: 0
    }"
}
System.Exception {
    Microsoft.AspNet.SignalR.Client.HttpClientException
}

Итак, вопрос в том, куда мне go посмотреть, чтобы выяснить, почему сервер SignalR выбрасывает 500 ?

И почему это работает в старой платформе, а не в новой?

Единственное структурное различие, которое я вижу, состоит в том, что в новой платформе вызывается метод Start () от таймера истекшего событияHandler. Может ли это иметь значение?


FWIW: Я попытался инициализировать трассировку сигнала в соответствии с инструкциями здесь:

https://docs.microsoft.com/en-us/aspnet/signalr/overview/testing-and-debugging/enabling-signalr-tracing

Используя старый работающий фреймворк, я вижу:

SignalR.SqlMessageBus Информация: 0: Установленные объекты SignalR SQL SignalR.SqlMessageBus Verbose: 0: Создано DbCommand: CommandType = Text, CommandText = SELECT [PayloadId] FROM [SignalR]. [Messages_0_Id], Parameters = SignalR.ScaleoutMessageBus Информация: 0: Stream (0) - измененное состояние с исходного на открытое SignalR.SqlMessageBus Verbose: 0: поток 0: SqlReceiver запущен, начальный идентификатор полезной нагрузки = 4188906 SignalR.SqlMessageBus Verbose: 0: Поток 0: выполнение считывателя получения, параметр начального идентификатора полезной нагрузки = 4188906

SignalR.SqlMessageBus Verbose: 0: Поток 0: запуск SQL приемник уведомлений SignalR.SqlMessageBus Verbose: 0: Поток 0: SQL прослушиватель уведомлений запущен

Использование новой инфраструктуры, которая не:

* 10 53 *

SignalR.SqlMessageBus Информация: 0: объекты SignalR SQL установлены SignalR.SqlMessageBus Подробно: 0: создано DbCommand: CommandType = Text, CommandText = SELECT [PayloadId] FROM [SignalR]. [Messages_0_Id], параметры .ScaleoutMessageBus Информация: 0: Stream (0) - измененное состояние с Начального на Открытое. SignalR.SqlMessageBus. Подробно: 0: Поток 0: SqlReceiver запущен, начальный идентификатор полезной нагрузки = 4188977 SignalR.SqlMessageBus. Подробный: 0: Поток 0: выполнение считывающего устройства, начальное. Параметр полезной нагрузки = 4188977

SignalR.SqlMessageBus Подробный: 0: Поток 0: Запуск SQL прослушивателя уведомлений

Другими словами, в новом фреймворке мы видим «Запуск SQL слушателя уведомлений», но мы никогда не видим «SQL слушатель уведомлений запущен».

Есть идеи, почему он не запускается?

Или где я могу посмотреть, почему он не запускается?

Ответы [ 2 ]

0 голосов
/ 01 апреля 2020

Я до сих пор не знаю, как получить реальную информацию о том, что именно происходит внутри SignalR.

Но я решил свою проблему.

Мой стартовый код создал прокси-сервер-концентратор таким образом:

this.ticketLockSignalRHubProxy = this.signalRConnection.CreateHubProxy("TicketLockSignalRHub");

И моя проблема заключалась в том, что было два экземпляра класса TicketLockSignalRHub, один в загрузочной сборке и один в сборке, содержащей метод KtOverseer.doMain(). Если бы я включил вызов KtOverseer.doMain(), даже если бы я его не вызывал, я бы загрузил вторую сборку, SignalR увидел бы два класса TicketLockSignalRHub и выдал исключение.

Удаление или переименование один из классов-концентраторов решает проблему,

0 голосов
/ 30 марта 2020

Обычно я вижу всплывающее окно AggregatedException, когда асинхронная задача c выдает ошибку и неправильно обрабатывается / разворачивается. Похоже, вы все делаете syn c, поэтому возможно ли, что вы вызываете asyn c где-нибудь?

Кроме того, агрегированные исключения могут быть распакованы. Это один пример: https://docs.microsoft.com/en-us/dotnet/api/system.aggregateexception.flatten?view=netframework-4.8. Или Уплощение исключений AggregateException для обработки .

Вас также может заинтересовать увеличение детализации ведения журнала SigR: https://docs.microsoft.com/en-us/aspnet/core/signalr/diagnostics?view=aspnetcore-3.1

Надеюсь помогает!

...