Fixed: Multiple SignalR Improvements

Support for serverSentEvents, connection optimizations

Co-Authored-By: taloth <taloth@users.noreply.github.com>
pull/840/head
Qstick 5 years ago
parent 184ab745ae
commit 3ebbf6ff83

@ -84,7 +84,7 @@ class SignalRConnector extends Component {
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
this.signalRconnectionOptions = { transport: ['webSockets', 'longPolling'] }; this.signalRconnectionOptions = { transport: ['webSockets', 'serverSentEvents', 'longPolling'] };
this.signalRconnection = null; this.signalRconnection = null;
this.retryInterval = 1; this.retryInterval = 1;
this.retryTimeoutId = null; this.retryTimeoutId = null;

@ -25,6 +25,8 @@ namespace Lidarr.Http
public void Handle(ModelEvent<TModel> message) public void Handle(ModelEvent<TModel> message)
{ {
if (!_signalRBroadcaster.IsConnected) return;
if (message.Action == ModelAction.Deleted || message.Action == ModelAction.Sync) if (message.Action == ModelAction.Deleted || message.Action == ModelAction.Sync)
{ {
BroadcastResourceChange(message.Action); BroadcastResourceChange(message.Action);
@ -35,6 +37,8 @@ namespace Lidarr.Http
protected void BroadcastResourceChange(ModelAction action, int id) protected void BroadcastResourceChange(ModelAction action, int id)
{ {
if (!_signalRBroadcaster.IsConnected) return;
if (action == ModelAction.Deleted) if (action == ModelAction.Deleted)
{ {
BroadcastResourceChange(action, new TResource { Id = id }); BroadcastResourceChange(action, new TResource { Id = id });
@ -48,6 +52,8 @@ namespace Lidarr.Http
protected void BroadcastResourceChange(ModelAction action, TResource resource) protected void BroadcastResourceChange(ModelAction action, TResource resource)
{ {
if (!_signalRBroadcaster.IsConnected) return;
if (GetType().Namespace.Contains("V1")) if (GetType().Namespace.Contains("V1"))
{ {
var signalRMessage = new SignalRMessage var signalRMessage = new SignalRMessage
@ -64,6 +70,8 @@ namespace Lidarr.Http
protected void BroadcastResourceChange(ModelAction action) protected void BroadcastResourceChange(ModelAction action)
{ {
if (!_signalRBroadcaster.IsConnected) return;
if (GetType().Namespace.Contains("V1")) if (GetType().Namespace.Contains("V1"))
{ {
var signalRMessage = new SignalRMessage var signalRMessage = new SignalRMessage

@ -16,9 +16,14 @@ namespace NzbDrone.Host.Owin.MiddleWare
SignalRDependencyResolver.Register(container); SignalRDependencyResolver.Register(container);
SignalRJsonSerializer.Register(); SignalRJsonSerializer.Register();
// Half the default time (110s) to get under nginx's default 60 proxy_read_timeout // Note there are some important timeouts involved here:
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(55); // nginx has a default 60 sec proxy_read_timeout, this means the connection will be terminated if the server doesn't send anything within that time.
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromMinutes(3); // Previously we lowered the ConnectionTimeout from 110s to 55s to remedy that, however all we should've done is set an appropriate KeepAlive.
// By default KeepAlive is 1/3rd of the DisconnectTimeout, which we set incredibly high 5 years ago, resulting in KeepAlive being 1 minute.
// So when adjusting these values in the future, please keep that all in mind.
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(110);
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(180);
GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(30);
} }
public void Attach(IAppBuilder appBuilder) public void Attach(IAppBuilder appBuilder)

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Infrastructure; using Microsoft.AspNet.SignalR.Infrastructure;
@ -12,6 +12,7 @@ namespace NzbDrone.SignalR
{ {
public interface IBroadcastSignalRMessage public interface IBroadcastSignalRMessage
{ {
bool IsConnected { get; }
void BroadcastMessage(SignalRMessage message); void BroadcastMessage(SignalRMessage message);
} }
@ -21,6 +22,7 @@ namespace NzbDrone.SignalR
private static string API_KEY; private static string API_KEY;
private readonly Dictionary<string, string> _messageHistory; private readonly Dictionary<string, string> _messageHistory;
private HashSet<string> _connections = new HashSet<string>();
public NzbDronePersistentConnection(IConfigFileProvider configFileProvider) public NzbDronePersistentConnection(IConfigFileProvider configFileProvider)
{ {
@ -28,6 +30,16 @@ namespace NzbDrone.SignalR
_messageHistory = new Dictionary<string, string>(); _messageHistory = new Dictionary<string, string>();
} }
public bool IsConnected
{
get
{
lock (_connections)
{
return _connections.Count != 0;
}
}
}
public void BroadcastMessage(SignalRMessage message) public void BroadcastMessage(SignalRMessage message)
{ {
@ -59,14 +71,34 @@ namespace NzbDrone.SignalR
protected override Task OnConnected(IRequest request, string connectionId) protected override Task OnConnected(IRequest request, string connectionId)
{ {
lock (_connections)
{
_connections.Add(connectionId);
}
return SendVersion(connectionId); return SendVersion(connectionId);
} }
protected override Task OnReconnected(IRequest request, string connectionId) protected override Task OnReconnected(IRequest request, string connectionId)
{ {
lock (_connections)
{
_connections.Add(connectionId);
}
return SendVersion(connectionId); return SendVersion(connectionId);
} }
protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
{
lock (_connections)
{
_connections.Remove(connectionId);
}
return base.OnDisconnected(request, connectionId, stopCalled);
}
private Task SendVersion(string connectionId) private Task SendVersion(string connectionId)
{ {
return Context.Connection.Send(connectionId, new SignalRMessage return Context.Connection.Send(connectionId, new SignalRMessage

@ -13,6 +13,7 @@ namespace NzbDrone.SignalR
{ {
_serializerSettings = Json.GetSerializerSettings(); _serializerSettings = Json.GetSerializerSettings();
_serializerSettings.ContractResolver = new SignalRContractResolver(); _serializerSettings.ContractResolver = new SignalRContractResolver();
_serializerSettings.Formatting = Formatting.None; // ServerSentEvents doesn't like newlines
_serializer = JsonSerializer.Create(_serializerSettings); _serializer = JsonSerializer.Create(_serializerSettings);

Loading…
Cancel
Save