para microsoft gratis desarrolladores cuenta .net azure system.diagnostics azure-worker-roles

.net - microsoft - portal azure



El rol de trabajador de Windows Azure no pasa la primera línea de código (5)

Tengo un rol de trabajador que funciona perfectamente en desarrollo pero no funciona cuando se implementa. "Does not work" es bastante vago, pero eso es todo lo que tengo que hacer ya que no veo ningún error ni nada (en el registro de eventos de todos modos, tal vez haya otro lugar donde pueda mirar). He agregado algunas declaraciones de seguimiento a mi código y veo que sale el primero, pero ninguno de los otros.

Código WorkerRole:

public class WorkerRole : RoleEntryPoint { #region Member variables private IWindsorContainer _container; private IJob[] _jobs; #endregion #region Methods public override bool OnStart() { ConfigureDiagnostics(); Trace.WriteLine("WorkerRole.OnStart()"); try { Initialize(); Trace.WriteLine("Resolving jobs..."); _jobs = _container.ResolveAll<IJob>(); StartJobs(); return base.OnStart(); } catch (Exception ex) { TraceUtil.TraceException(ex); throw; } finally { Trace.WriteLine("WorkerRole.OnStart - Complete"); Trace.Flush(); } } /// <summary> /// Sets up diagnostics. /// </summary> private void ConfigureDiagnostics() { DiagnosticMonitorConfiguration dmc = DiagnosticMonitor.GetDefaultInitialConfiguration(); dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1); dmc.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose; DiagnosticMonitor.Start(Constants.DiagnosticsConnectionString, dmc); } /// <summary> /// Sets up the IoC container etc. /// </summary> private void Initialize() { Trace.WriteLine("WorkerRole.Initialize()"); try { Trace.WriteLine("Configuring AutoMapper..."); AutoMapperConfiguration.Configure(); Trace.WriteLine("Configuring Windsor..."); _container = new WindsorContainer(); Trace.WriteLine(string.Format("Installing assemblies from directory...{0}", Path.Combine(Environment.GetEnvironmentVariable(Constants.RoleRoot), Constants.AppRoot))); _container.Install(FromAssembly.InDirectory( new AssemblyFilter(Path.Combine(Environment.GetEnvironmentVariable(Constants.RoleRoot), Constants.AppRoot)))); Trace.WriteLine(string.Format("Setting the default connection limit...")); ServicePointManager.DefaultConnectionLimit = 12; } finally { Trace.WriteLine("WorkerRole.Initialize - Complete"); } } /// <summary> /// Starts all of the jobs. /// </summary> private void StartJobs() { Trace.WriteLine("WorkerRole.StartJobs()"); try { foreach (IJob job in _jobs) { job.Start(); } } finally { Trace.WriteLine("WorkerRole.StartJobs - Complete"); } } public override void OnStop() { Trace.WriteLine("WorkerRole.OnStop()"); try { foreach (IJob job in _jobs) { job.Stop(); } _container.Dispose(); } finally { Trace.WriteLine("WorkerRole.OnStop - Complete"); } } #endregion #region Private util classes public static class AutoMapperConfiguration { public static void Configure() { Mapper.Initialize(x => x.AddProfile<ModelProfile>()); } } #endregion }

Código TraceUtil:

public static class TraceUtil { public static void TraceException(Exception ex) { StringBuilder buffer = new StringBuilder(); while (ex != null) { buffer.AppendFormat("{0} : ", ex.GetType()); buffer.AppendLine(ex.Message); buffer.AppendLine(ex.StackTrace); ex = ex.InnerException; } Trace.TraceError(buffer.ToString()); } }

Config:

<?xml version="1.0" encoding="utf-8" ?> <configuration> ... <system.diagnostics> <trace autoflush="true"> <listeners> <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics"> <filter type="" /> </add> </listeners> </trace> </system.diagnostics> </configuration>

Una vez que el trabajador ha comenzado, si miro en WADLogsTable, todo lo que veo es "WorkerRole.OnStart ()" ¡y nada más!

Se agradecerá cualquier idea sobre cuál podría ser el problema o cómo solucionarlo.

Actualización: si detengo el rol, tampoco veo ninguna de las instrucciones de depuración del método OnStop() .

Actualización: debo tener algo configurado incorrectamente con mis diagnósticos. Pensé que estaba viendo que mi depuración salga correctamente cuando se depura localmente, pero resulta que no lo soy. Veo todo en la ventana de salida, pero no veo todo en la tabla de almacenamiento. Estoy viendo las siguientes entradas en desarrollo:

WorkerRole.OnStart() WorkerRole.Initialize() Configuring AutoMapper...

Me doy cuenta de que la salida de rastreo solo se carga periódicamente, pero he esperado 5 minutos más o menos, así que creo que esto debería ser lo suficientemente largo, ya que lo tengo configurado en 1 minuto.

Actualización: según lo sugerido por @kwill en la sección de comentarios, intenté agregar un detector de seguimiento de archivos de la siguiente manera:

<system.diagnostics> <trace autoflush="true"> <listeners> <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics"> </add> <add name="File" type="System.Diagnostics.TextWriterTraceListener" initializeData="C:/TextWriterOutput.log" /> </listeners> </trace> </system.diagnostics>

Esto funciona bien en mi entorno de desarrollo y parece más confiable, así como obtengo toda la depuración que esperaba. Sin embargo, cuando lo despliegue en etapas, el archivo TextWriterOutput.log ¡ni siquiera se crea!

Realmente necesito una forma confiable de eliminar errores de mi rol de trabajador para poder solucionar el problema final, que es que mis trabajos no están funcionando, en este momento aún no tengo idea de lo que están tratando de hacer, ya que no se puede depurar!

Actualización: estoy bastante seguro de que la idea de falta de DLL sugerida por la mayoría de las personas no es el problema. Para demostrarlo con suerte, anulé el método run como se muestra a continuación y veo que sale la depuración "Heartbeat ...". Me parece que la funcionalidad de diagnóstico o al menos la forma en que la configuro no es confiable, lo que me impide investigar por qué mis trabajos no se están ejecutando.

public override void Run() { Trace.WriteLine("LearningMiles.JobProcessor.WorkerRole.Run()", "Information"); try { while (true) { Thread.Sleep(10000); Trace.WriteLine("Heartbeat...", "Verbose"); } } catch (Exception ex) { TraceUtil.TraceException(ex); throw; } finally { Trace.WriteLine("LearningMiles.JobProcessor.WorkerRole.Run() - Complete", "Information"); } }

Actualización: ahora he publicado este problema en el foro de Windows Azure MSDN .

Actualización: Como se sugirió en los comentarios, ahora he intentado eliminar todo el código ''útil''. En desarrollo, esto dio como resultado que todo el resultado de la depuración sea Luego intenté simplemente eliminar la llamada a AutomapperConfiguration.Configure() ya que antes no veía nada que saliera después de esa llamada. Esto dio lugar a que algunas de las declaraciones de seguimiento no aparecieran nuevamente. Es importante destacar, sin embargo, que estaba viendo las declaraciones de seguimiento que he puesto en los "trabajos". Dado que son los trabajos que no se ejecutan los que finalmente quiero resolver, implementé esa versión del código para la puesta en escena, pero allí solo veo el trazo OnStart () y el trazo "heartbeat". No creo que esto realmente ayude, pero tal vez le dará a alguien algunas ideas.


¿Estás diciendo que obtienes el rastro

"WorkerRole.OnStart()"

pero no el rastro

"WorkerRole.Initialize()"

Eso parece altamente improbable ya que las dos declaraciones de rastreo se ejecutan una después de la otra.

¿Ha intentado con RDP a la máquina virtual para ver si el proceso WaWorkerHost.exe se bloquea?


Dado que se llama a la traza OnStart (), pero no a Initialize (), supongo que uno de los ensamblados a los que hace referencia el código en Initialize () no se está copiando a la implementación. Recuerde que .Net JIT-compila un método a la vez, y debido a ese comportamiento, tendría sentido que aparezca el mensaje de seguimiento de OnStart (ya que hay pocos ensambles de Windows Azure y .Net framework referenciados hasta ese punto) . Sin embargo, cuando el CLR pasa a JIT el método Initialize, intenta cargar varios ensamblajes de terceros (AutoMapper y Windsor) que pueden no estar empaquetados correctamente, pero que pueden estar GACced o disponibles localmente cuando se ejecuta el emulador.

Un par de cosas para probar:

  1. Manualmente empaquete su implementación desde Visual Studio y eche un vistazo cuidadoso al resultado de compilación. Muchas veces, VS detectará sus ensamblajes faltantes y le dirá (desafortunadamente como una advertencia, no un error) que se está perdiendo algo.
  2. Si no ve nada en el resultado que parezca obvio, eche un vistazo al archivo cspkg en sí (recuerde que es solo un archivo ZIP con más archivos ZIP) y asegúrese de que los ensamblados a los que hace referencia su aplicación / rol estén allí. . Alternativamente, conéctese a la máquina virtual y verifique el aspecto de esos conjuntos.
  3. Es posible que pueda encontrar una entrada en el registro de eventos de la VM que muestre que su aplicación no pudo cargar un ensamblaje.

Creo que Doug Rohrer tiene la respuesta correcta. Existe una alta probabilidad de que le falten archivos DLL en el proyecto, lo cual se puede verificar examinando el paquete. Tenga en cuenta que el paquete debe crearse sin cifrar si está utilizando una versión anterior de 1.6 SDK.

Me gustaría agregar dos puntos.

  1. Si configura "Copiar local" en verdadero, en algunos casos, solo funciona si el archivo de proyecto se edita de forma manual y se le da explícitamente la ruta completa del ensamblaje. (Esto ocurre cuando el ensamblaje también está presente en el GAC de la máquina local).

  2. Si las dependencias a las que se hace referencia están en un ensamblado que, a su vez, es referenciado por el conjunto de roles de Azure, las dependencias no obtienen copias. En ese caso, estas dependencias también deben agregarse al conjunto de funciones aunque no las use. (Esto es un poco difícil de creer pero me encontré con este problema).


La mayoría de las veces, la causa raíz de problemas como este es la falta de dependencias. Ya hay buenas sugerencias en este frente en respuestas anteriores.

Los registros de seguimiento se transfieren al almacenamiento de Azure una vez por minuto según su configuración. Si su proceso de trabajo falla, puede perder algunos de los últimos mensajes de rastreo. Para solucionar este problema, intente agregar un Thread.Sleep (TimeSpan.FromMinutes (2)) en sus manejadores de excepciones para asegurarse de que el registro de excepciones se vacíe al almacenamiento.

Finalmente, si todo lo demás falla, le sugiero que intente depurar su función con WinDbg. Habilite Escritorio remoto para su función. Inicie sesión en el rol y desactive la navegación segura de IE para que pueda instalar cosas. A continuación, descargue e instale Debugging Tools para Windows desde http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=8279 . Este paquete contiene todo el SDK de Windows, pero puede seleccionar instalar las herramientas de depuración solo para Windows.

Luego ejecute WinDbg y conéctelo a WaWorkerHost.exe. En WinDbg, hazlo

.loadby sos clr // load the SOS extension that allows you to do managed debugging sxe clr // break on CLR exceptions g // continue

WinDbg ahora debe interrumpir la ejecución cuando hay una excepción CLR. Cuando se rompe, ejecuta

!PrintException

para ver los detalles de la excepción. Es posible que desee agregar otra llamada Thread.Sleep en su inicio de función para darle tiempo para adjuntar el depurador antes de que el proceso finalice.


Gracias a una respuesta en el foro de MSDN , pude solucionar y resolver mi problema.

La razón por la cual mis trabajos no se estaban ejecutando se debió a la siguiente línea:

_container.Install(FromAssembly.InDirectory( new AssemblyFilter(Path.Combine(Environment.GetEnvironmentVariable(Constants.RoleRoot), Constants.AppRoot))));

El rol raíz en la etapa es E :. Path.Combine () tiene una implementación oscura sobre la que puede obtener más información en esta respuesta SO . Lo que esto significaba era que Castle estaba buscando asambleas en E: approot en vez de E: / approot como esperaba. Ahora estoy construyendo la ruta de acceso con el siguiente método:

private string GetAppRoot() { string root = Environment.GetEnvironmentVariable(Constants.RoleRoot); if (root.EndsWith(Path.VolumeSeparatorChar.ToString())) root += Path.DirectorySeparatorChar; return Path.Combine(root, Constants.AppRoot); }

Eso ha resuelto mi problema principal y ahora veo que los trabajos se ejecutan como se esperaba.

Solo pude solucionar este problema ejecutando la función de trabajador en un contexto de ejecución elevado para que mis datos de seguimiento se pudieran escribir en un archivo. Todavía no sé por qué, y me gustaría saber si hay alguna idea de por qué, las declaraciones de rastreo no se transfirieron correctamente al almacenamiento.