2015-07-28 10 views
14

Mam następujący kod w moim Startup.SignalR.cs:MVC5 wisi na MapSignalR po ponownym podłączeniu po AppPool cykli

using Microsoft.AspNet.SignalR; 
using Owin; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace Admin 
{ 
    public partial class Startup 
    { 
     public void ConfigureSignalR(IAppBuilder app) 
     { 
      var Config = new HubConfiguration() 
      { 
       EnableDetailedErrors = false, 
       Resolver = new DefaultDependencyResolver() 
      }; 

#if DEBUG 
      Config.EnableDetailedErrors = true; 
#endif 
      // Any connection or hub wire up and configuration should go here 
      app.MapSignalR(); 

      GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(600); 
     } 
    } 
} 

Podczas pierwszego ładowania aplikacji, wszystko idzie dobrze, jednak gdy wątek jest dozwolony spać (od lewej do ~ 10min) AppPool zawraca i nitka utknie na tej linii:

app.MapSignalR(); 

IDE tkwi z zieloną strzałką i This is the next statement to execute when this thread returns from the current function.. Jednak nie mam pojęcia, co to jest current function.

Próba wglądu do wszelkich wyników lokalnych zmiennych w Cannot evaluate expression because a native frame is on top of the call stack. jednak stosu wywołań pokazuje: Admin.dll!Admin.Startup.ConfigureSignalR(Owin.IAppBuilder app) Line 25 w górnej ramce ...

Kod nigdy nie wyjdzie z tego stanu i AppPool musi być całkowicie wznowiona po ponownym uruchomieniu debugowania sesja.

Ktoś ma jakieś wytłumaczenie tego scenariusza?

Dodatkowe informacje: Po włączeniu Debug => Windows => Parrallel Stosy widzę bardziej szczegółowy ślad stosu:

[Managed to Native Transition] 
mscorlib.dll!Microsoft.Win32.RegistryKey.OpenSubKey(string name, bool writable) 
mscorlib.dll!Microsoft.Win32.RegistryKey.OpenSubKey(string name) 
System.dll!System.Diagnostics.PerformanceCounterLib.FindCustomCategory(string category, out System.Diagnostics.PerformanceCounterCategoryType categoryType) 
System.dll!System.Diagnostics.PerformanceCounterLib.IsCustomCategory(string machine, string category) 
System.dll!System.Diagnostics.PerformanceCounter.InitializeImpl() 
System.dll!System.Diagnostics.PerformanceCounter.PerformanceCounter(string categoryName, string counterName, string instanceName, bool readOnly) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Infrastructure.PerformanceCounterManager.LoadCounter(string categoryName, string counterName, string instanceName, bool isReadOnly) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Infrastructure.PerformanceCounterManager.LoadCounter(string categoryName, string counterName, bool isReadOnly) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Infrastructure.PerformanceCounterManager.SetCounterProperties() 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Infrastructure.PerformanceCounterManager.Initialize(string instanceName, System.Threading.CancellationToken hostShutdownToken) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Hosting.HostDependencyResolverExtensions.InitializePerformanceCounters(Microsoft.AspNet.SignalR.IDependencyResolver resolver, string instanceName, System.Threading.CancellationToken hostShutdownToken) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Hosting.HostDependencyResolverExtensions.InitializeHost(Microsoft.AspNet.SignalR.IDependencyResolver resolver, string instanceName, System.Threading.CancellationToken hostShutdownToken) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.UseSignalRMiddleware<Microsoft.AspNet.SignalR.Owin.Middleware.HubDispatcherMiddleware>(Owin.IAppBuilder builder, object[] args) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.RunSignalR(Owin.IAppBuilder builder, Microsoft.AspNet.SignalR.HubConfiguration configuration) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.MapSignalR.AnonymousMethod__0(Owin.IAppBuilder subApp) 
Microsoft.Owin.dll!Owin.MapExtensions.Map(Owin.IAppBuilder app, Microsoft.Owin.PathString pathMatch, System.Action<Owin.IAppBuilder> configuration) 
Microsoft.Owin.dll!Owin.MapExtensions.Map(Owin.IAppBuilder app, string pathMatch, System.Action<Owin.IAppBuilder> configuration) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.MapSignalR(Owin.IAppBuilder builder, string path, Microsoft.AspNet.SignalR.HubConfiguration configuration) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.MapSignalR(Owin.IAppBuilder builder, Microsoft.AspNet.SignalR.HubConfiguration configuration) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.MapSignalR(Owin.IAppBuilder builder) 
Admin.dll!Admin.Startup.ConfigureSignalR(Owin.IAppBuilder app) Line 25 
+1

To wygląda podobnie do tego: https://github.com/SignalR/SignalR/issues/3414 – Pawel

+0

Ja też doświadczam tego samego problemu. – JacobE

Odpowiedz

5

Jak wspomniano Paweł, udało mi się rozwiązać mój problem z wykorzystaniem manekin licznik wydajności udokumentowane tutaj: https://github.com/SignalR/SignalR/issues/3414

// Global.asmx 
var tempCounterManager = new TempPerformanceCounterManager(); 
GlobalHost.DependencyResolver.Register(typeof (IPerformanceCounterManager),() => tempCounterManager); 

[....] 

// Helper Class 
public class TempPerformanceCounterManager : IPerformanceCounterManager 
{ 
    private readonly static PropertyInfo[] _counterProperties = GetCounterPropertyInfo(); 
    private readonly static IPerformanceCounter _noOpCounter = new NoOpPerformanceCounter(); 

    public TempPerformanceCounterManager() 
    { 
     foreach (var property in _counterProperties) 
     { 
      property.SetValue(this, new NoOpPerformanceCounter(), null); 
     } 
    } 

    public void Initialize(string instanceName, CancellationToken hostShutdownToken) 
    { 
    } 

    public IPerformanceCounter LoadCounter(string categoryName, string counterName, string instanceName, bool isReadOnly) 
    { 
     return _noOpCounter; 
    } 

    internal static PropertyInfo[] GetCounterPropertyInfo() 
    { 
     return typeof(TempPerformanceCounterManager) 
      .GetProperties() 
      .Where(p => p.PropertyType == typeof(IPerformanceCounter)) 
      .ToArray(); 
    } 
    public IPerformanceCounter ConnectionsConnected { get; set; } 
    public IPerformanceCounter ConnectionsReconnected { get; set; } 
    public IPerformanceCounter ConnectionsDisconnected { get; set; } 
    public IPerformanceCounter ConnectionsCurrentForeverFrame { get; private set; } 
    public IPerformanceCounter ConnectionsCurrentLongPolling { get; private set; } 
    public IPerformanceCounter ConnectionsCurrentServerSentEvents { get; private set; } 
    public IPerformanceCounter ConnectionsCurrentWebSockets { get; private set; } 
    public IPerformanceCounter ConnectionsCurrent { get; private set; } 
    public IPerformanceCounter ConnectionMessagesReceivedTotal { get; private set; } 
    public IPerformanceCounter ConnectionMessagesSentTotal { get; private set; } 
    public IPerformanceCounter ConnectionMessagesReceivedPerSec { get; private set; } 
    public IPerformanceCounter ConnectionMessagesSentPerSec { get; private set; } 
    public IPerformanceCounter MessageBusMessagesReceivedTotal { get; private set; } 
    public IPerformanceCounter MessageBusMessagesReceivedPerSec { get; private set; } 
    public IPerformanceCounter ScaleoutMessageBusMessagesReceivedPerSec { get; private set; } 
    public IPerformanceCounter MessageBusMessagesPublishedTotal { get; private set; } 
    public IPerformanceCounter MessageBusMessagesPublishedPerSec { get; private set; } 
    public IPerformanceCounter MessageBusSubscribersCurrent { get; private set; } 
    public IPerformanceCounter MessageBusSubscribersTotal { get; private set; } 
    public IPerformanceCounter MessageBusSubscribersPerSec { get; private set; } 
    public IPerformanceCounter MessageBusAllocatedWorkers { get; private set; } 
    public IPerformanceCounter MessageBusBusyWorkers { get; private set; } 
    public IPerformanceCounter MessageBusTopicsCurrent { get; private set; } 
    public IPerformanceCounter ErrorsAllTotal { get; private set; } 
    public IPerformanceCounter ErrorsAllPerSec { get; private set; } 
    public IPerformanceCounter ErrorsHubResolutionTotal { get; private set; } 
    public IPerformanceCounter ErrorsHubResolutionPerSec { get; private set; } 
    public IPerformanceCounter ErrorsHubInvocationTotal { get; private set; } 
    public IPerformanceCounter ErrorsHubInvocationPerSec { get; private set; } 
    public IPerformanceCounter ErrorsTransportTotal { get; private set; } 
    public IPerformanceCounter ErrorsTransportPerSec { get; private set; } 
    public IPerformanceCounter ScaleoutStreamCountTotal { get; private set; } 
    public IPerformanceCounter ScaleoutStreamCountOpen { get; private set; } 
    public IPerformanceCounter ScaleoutStreamCountBuffering { get; private set; } 
    public IPerformanceCounter ScaleoutErrorsTotal { get; private set; } 
    public IPerformanceCounter ScaleoutErrorsPerSec { get; private set; } 
    public IPerformanceCounter ScaleoutSendQueueLength { get; private set; } 
} 

internal class NoOpPerformanceCounter : IPerformanceCounter 
{ 
    public string CounterName 
    { 
     get 
     { 
      return GetType().Name; 
     } 
    } 
    public long Decrement() 
    { 
     return 0; 
    } 
    public long Increment() 
    { 
     return 0; 
    } 
    public long IncrementBy(long value) 
    { 
     return 0; 
    } 
    public long RawValue 
    { 
     get { return 0; } 
     set { } 
    } 
    public void Close() 
    { 
    } 
    public void RemoveInstance() 
    { 
    } 
    public CounterSample NextSample() 
    { 
     return CounterSample.Empty; 
    } 
} 
+0

Proszę zobaczyć odpowiedź z @eladm poniżej, ponieważ jest to oficjalna poprawka https://github.com/SignalR/SignalR/pull/3609 w gałęzi dev SignalR. Nie wydany jeszcze w wersji 2.2.0. – bigbearzhu

11

kolejna poprawka do tego, z tego blogu: http://www.zpqrtbnk.net/posts/appdomains-threads-cultureinfos-and-paracetamol

app.SanitizeThreadCulture(); 

public static void SanitizeThreadCulture(this IAppBuilder app) 
{ 
     var currentCulture = CultureInfo.CurrentCulture; 

     // at the top of any culture should be the invariant culture, 
     // find it doing an .Equals comparison ensure that we will 
     // find it and not loop endlessly 
     var invariantCulture = currentCulture; 
     while (invariantCulture.Equals(CultureInfo.InvariantCulture) == false) 
      invariantCulture = invariantCulture.Parent; 

     if (ReferenceEquals(invariantCulture, CultureInfo.InvariantCulture)) 
      return; 

     var thread = Thread.CurrentThread; 
     thread.CurrentCulture = CultureInfo.GetCultureInfo(thread.CurrentCulture.Name); 
     thread.CurrentUICulture = CultureInfo.GetCultureInfo(thread.CurrentUICulture.Name); 
} 
2

znalazłem rozwiązanie tutaj: github.com/SignalR/SignalR/issues/3414 próbkę Snip:

public void Configuration(IAppBuilder app) 
{ 
    var task = Task.Run(() => app.MapSignalR()); 
    task.Wait(300); 
    //try again if it fails just to be sure ;) 
    if (task.IsCanceled) Task.Run(() => app.MapSignalR()).Wait(300); 
} 
+1

Pierwotnie wypróbowałem to podejście i to nie pomogło, wciąż zawieszałem się podczas pierwszego 'Task.Run()' mimo, że miał on czas oczekiwania na 300ms. –

+0

działa idealnie dla mnie i wydaje mi się czystszy – SQueek

Powiązane problemy