【发布时间】:2020-04-01 23:49:56
【问题描述】:
我们为后台守护程序构建了一个框架,以帮助它们保持一致的行为,因此我们不必不断重写相同的代码。
当然,十年后我们建造了一个新的。
旧框架中的一个应用程序是 SignalR 信号应用程序。它在 Microsoft 的 Owin 中托管 SignalR 实例,然后定期检查数据库是否需要推送,然后调用 SignalR 网站,然后使用配置的背板与正在运行的任何其他网络服务器通信,然后推送出去到各种网络客户端。
有点复杂,但确实有效。
现在我的工作是将其移至新的后台应用程序框架,当我尝试启动网络应用程序时遇到 HTTP 500 错误。
新守护程序中的代码与旧应用程序中的代码几乎相同,我不明白为什么它在一个中工作而在另一个中无效。
两个框架的工作方式是每个守护进程都有一个重复调用的 doWork() 函数。在旧应用程序中,有一个会调用 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
}
我们将 this 的一个实例存储在一个静态成员中,以便 work() 函数可以访问它:
public class Utils
{
public static SignalRWebApp signalRWebApp;
}
然后我们将启动代码包装在 using() 中,以便它在应用程序运行时存在。注意 - 如果您查看上面的 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
}
所以问题是,我该去哪里找出 SignalR 服务器抛出 500 的原因?
为什么这在旧框架中有效,而在新框架中无效?
我能看到的唯一结构差异是,在新框架中,Start() 方法是从 Timer ElapsedEventHandler 调用的。这会有所作为吗?
FWIW:我尝试按照此处的说明初始化信号器跟踪:
使用有效的旧框架,我看到了:
SignalR.SqlMessageBus 信息:0:已安装 SignalR SQL 对象 SignalR.SqlMessageBus 详细:0:创建 DbCommand: CommandType=文本,CommandText=SELECT [PayloadId] FROM [SignalR].[Messages_0_Id],参数= SignalR.ScaleoutMessageBus 信息:0:Stream(0) - 将状态从初始更改为打开 SignalR.SqlMessageBus 详细:0:流 0:SqlReceiver 已启动, 初始负载 id=4188906 SignalR.SqlMessageBus 详细:0:流 0 : 执行接收阅读器,初始payload ID参数=4188906
SignalR.SqlMessageBus 详细:0:流 0:启动 SQL 通知侦听器 SignalR.SqlMessageBus 详细:0:流 0: SQL 通知侦听器已启动
使用没有的新框架:
SignalR.SqlMessageBus 信息:0:已安装 SignalR SQL 对象 SignalR.SqlMessageBus 详细:0:创建 DbCommand: CommandType=文本,CommandText=SELECT [PayloadId] FROM [SignalR].[Messages_0_Id],参数= SignalR.ScaleoutMessageBus 信息:0:Stream(0) - 将状态从初始更改为打开 SignalR.SqlMessageBus 详细:0:流 0:SqlReceiver 已启动, 初始负载 id=4188977 SignalR.SqlMessageBus 详细:0:流 0 : 执行接收阅读器,初始payload ID参数=4188977
SignalR.SqlMessageBus 详细:0:流 0:启动 SQL 通知监听器
换句话说,在新框架中,我们看到“正在启动 SQL 通知侦听器”,但我们从未看到“SQL 通知侦听器已启动”。
关于为什么它没有开始的任何想法?
或者我可以从哪里找到它没有启动的原因?
【问题讨论】: