2014-04-15 9 views
6

Sto facendo fatica a capire perché Nancy non accetta richieste per circa 1 minuto. Ho approssimativamente 60 endpoint e tutti questi inizializzano molto rapidamente in modo che tutti i moduli vengano elaborati.Nancy lento per iniziare ad accettare le richieste

Ci sono motivi comuni per questo? O c'è un modo per rintracciare cosa sta succedendo?

EDIT

Logging di app start up

App Start 4/15/2014 11:03:48 AM 
App Start Complete 4/15/2014 11:03:48 AM 
Bootstrap 4/15/2014 11:04:19 AM 
Module 3 4/15/2014 11:06:37 AM 
Module 1 4/15/2014 11:06:37 AM 
Module 2 4/15/2014 11:06:37 AM 
Module 1 4/15/2014 11:06:37 AM 
Module 1 4/15/2014 11:06:37 AM 
Module 1 4/15/2014 11:06:37 AM 
Module 1 4/15/2014 11:06:37 AM 
Module 1 4/15/2014 11:06:37 AM 
Module 1 4/15/2014 11:06:38 AM 
Module 1 4/15/2014 11:06:38 AM 
Module 1 4/15/2014 11:06:38 AM 

Come visibile nei tempi c'è un ritardo prima bootstrap e anche prima dei moduli sono chiamati.

EDIT 2

La mia configurazione è Nancy (v0.22.2 costruito dalla fonte come chiave di forte era necessario, senza modifiche al codice) ASP.NET 4.5 utilizzando Web Form. Utilizzo di Visual Studio 2013 come IDE

+0

Non sono sicuro di aver compreso la configurazione: 60 punti finali e tutti i moduli sono inizializzati ma il bootstrapper viene chiamato dopo di essi? Che cosa? :) –

+0

@StevenRobbins Mi sono sbagliato ho aggiunto la registrazione alla mia startup aggiornerà la mia risposta con i dettagli – Dreamwalker

+0

aggiunta la mia configurazione nel caso sia rilevante – Dreamwalker

risposta

9

Penso di aver trovato quale fosse il problema. Il problema è con la funzionalità AutoRegister dal contenitore TinyIoC che Nancy utilizza.

Fondamentalmente all'avvio (prima richiesta) esegue la scansione di ogni assembly dell'AppDomain per registrare le dipendenze. Questo processo è molto lento: https://github.com/NancyFx/Nancy/issues/643

La soluzione è quella di registrare le dipendenze manualmente come indicato qui: https://github.com/NancyFx/Nancy/wiki/Bootstrapping-nancy

In pratica dovete solo per creare una classe nel progetto aspnet che eredita da DefaultNancyAspNetBootstrapper e l'override del metodo ConfigureApplicationContainer:

public class Bootstrapper : DefaultNancyAspNetBootstrapper 
{ 
    protected override void ConfigureApplicationContainer(TinyIoCContainer container) 
    { 
     // Register our app dependency as a normal singleton   

    } 
} 

Spero che questo aiuti,

+0

Ciao, grazie per il feedback, ti ​​darò una prova – Dreamwalker

+1

Questa è stata davvero la ragione per cui ho un sacco di grandi assemblee dipendenti. Il percorso super-duper felice non è stato così felice sembra;) – Dreamwalker

+0

Nancy è fantastica. –

0

La causa principale di lenta esecuzione di funzionalità AutoRegister a Nancy è enorme quantità di assiemi e tipi elaborati. Il secondo problema non è un codice ottimale per questo caso. L'attuale versione stabile di Nancy (1.4.3) ha il seguente codice https://github.com/NancyFx/Nancy/blob/1.x-WorkingBranch/src/Nancy/TinyIoc/TinyIoC.cs#L3092-L3094 Come risultato questa espressione di linq elaborata per ciascun tipo ... Per modificare questo comportamento è possibile utilizzare la classe seguente come base per Bootstrapper. Inoltre, è possibile velocizzare questo codice escludendo i propri assembly 3D party in AutoRegisterIgnoredAssemblies (vedere l'esempio nel codice).

Nel mio sistema aiuta ad aumentare la velocità di registrazione automatica di 521 volte da 50 secondi a 95 ms.

public class AutoRegistredBootstrapper : DefaultNancyBootstrapper 
{ 
    private readonly object AutoRegisterLock = new object(); 
    private void AutoRegister(TinyIoCContainer container, IEnumerable<Assembly> assemblies) 
    { 
     var ignoreChecks = new List<Func<Type, bool>>() 
     { 
      t => t.FullName.StartsWith("System.", StringComparison.Ordinal), 
      t => t.FullName.StartsWith("Microsoft.", StringComparison.Ordinal), 
      t => t.IsPrimitive(), 
      t => (t.GetConstructors(BindingFlags.Instance | BindingFlags.Public).Length == 0) && !(t.IsInterface() || t.IsAbstract()), 
      t => t.Assembly == typeof(NancyEngine).Assembly 
     }; 


     lock (AutoRegisterLock) 
     { 
      var thisType = this.GetType(); 
      var types = assemblies.SelectMany(a => AssemblyExtensions.SafeGetTypes(a)) 
       .Where(type => (type.DeclaringType != thisType) 
           && !type.IsGenericTypeDefinition()) 
       .Where(t => !ignoreChecks.Any(check => check(t))) 
       .ToList(); 

      var assignebleTypes = 
       types.Where(
         type => 
          type.IsClass() && (type.IsAbstract() == false) && (type != thisType)) 
        .Select(t => 
        { 
         // be careful with side effects in linq 
         container.Register(t); 
         return t; 
        }) 
        .Where(implementationType => implementationType.GetTypeInfo().ImplementedInterfaces.Any() || implementationType.BaseType != typeof(Object)) 
        .ToList(); 

      var abstractInterfaceTypes = types.Where(type => ((type.IsInterface() || type.IsAbstract()))); 

      foreach (var abstractInterfaceType in abstractInterfaceTypes) 
      { 
       var localType = abstractInterfaceType; 
       var implementations = 
        assignebleTypes.Where(implementationType => localType.IsAssignableFrom(implementationType)).ToList(); 

       if (implementations.Count > 1) 
       { 
        if (implementations.Count != implementations.Distinct().Count()) 
        { 
         var fullNamesOfDuplicatedTypes = string.Join(",\n", 
          implementations.GroupBy(i => i).Where(j => j.Count() > 1).Select(j => j.Key.FullName)); 

         throw new ArgumentException($"types: The same implementation type cannot be specified multiple times for {abstractInterfaceType.FullName}\n\n{fullNamesOfDuplicatedTypes}"); 
        } 

        foreach (var implementationType in implementations) 
        { 
         container.Register(abstractInterfaceType, implementationType, implementationType.FullName); 
        } 

       } 

       var firstImplementation = implementations.FirstOrDefault(); 
       if (firstImplementation != null) 
       { 
        container.Register(abstractInterfaceType, firstImplementation); 
       } 
      } 
     } 
    } 

    protected override IEnumerable<Func<Assembly, bool>> AutoRegisterIgnoredAssemblies 
    { 
     get 
     { 
      return DefaultAutoRegisterIgnoredAssemblies.Concat(new Func<Assembly, bool>[] 
      { 
       asm => asm.FullName.StartsWith("ICSharpCode.", StringComparison.Ordinal), 
       asm => asm.FullName.StartsWith("Ionic.", StringComparison.Ordinal), 
       asm => asm.FullName.StartsWith("CommandLine,", StringComparison.Ordinal) 
       // ADD THE REST OF 3D party libs that you don't use as dependencies 
      }); 
     } 
    } 

    protected override void ConfigureApplicationContainer(TinyIoCContainer container) 
    { 
     var currentDomainAssemblies = AppDomain.CurrentDomain.GetAssemblies(); 

     var ignoredAssemblies = this.AutoRegisterIgnoredAssemblies.ToList(); 
     var asmsForProcessing = currentDomainAssemblies.Where(a => !ignoredAssemblies.Any(ia => ia(a))).ToList(); 

     AutoRegister(container, asmsForProcessing); 
    } 

}