Dot-Net

Windows Azure Worker Role 沒有通過第一行程式碼

  • March 6, 2012

我有一個工人角色,在開發中完美地工作,但在部署時不起作用。“不起作用”相當模糊,但這就是我必須繼續做的所有事情,因為我沒有看到任何錯誤或任何東西(無論如何在事件日誌中 - 也許還有其他地方我可以查看)。我在我的程式碼中添加了一些跟踪語句,我看到第一個出現了,但其他的都沒有。

工人角色程式碼:

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
}

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());
   }
}

配置:

<?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>

一旦工人開始,如果我查看 WADLogsTable,我看到的只是“WorkerRole.OnStart()”,沒有別的!

任何有關問題可能是什麼或如何解決此問題的想法將不勝感激。

**更新:**如果我停止該角色,我也看不到該OnStop()方法中的任何調試語句。

**更新:**我的診斷必須有一些配置不正確。我以為我在本地調試時看到我的調試正確,但事實證明我不是。我在輸出視窗中看到了所有內容,但在儲存表中沒有看到所有內容。我在開發中看到以下條目:

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

我意識到跟踪輸出只是定期上傳,但我已經等了 5 分鐘左右,所以我認為這應該足夠長,因為我將它設置為 1 分鐘。

**更新:**正如@kwill 在評論部分所建議的,我嘗試添加一個文件跟踪偵聽器,如下所示:

 <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>

這在我的開發環境中執行良好,並且看起來更可靠,並且我得到了我期望的所有調試。但是,當我將其部署到登台時,甚至沒有創建 TextWriterOutput.log 文件!

我真的需要一種可靠的方法來從我的工人角色中進行調試,以便我可以解決最終問題,即我的工作無法正常工作 - 在這一點上,我仍然不知道他們甚至試圖做什麼,因為我無法進行任何調試!

**更新:**我很確定大多數人建議的缺失 dll 想法不是問題所在。為了希望證明這一點,我重寫了 run 方法,如下所示,我看到“Heartbeat …”調試出來了。在我看來,診斷功能或至少我配置它的方式是不可靠的,這使我無法調查究竟為什麼我的工作沒有執行。

   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");
       }
   }

**更新:**我現在已經在Windows Azure MSDN 論壇上交叉發布了這個問題。

**更新:**正如評論中所建議的,我現在嘗試刪除所有“有用”的程式碼。在開發中,這導致所有調試都被輸出。然後我嘗試刪除呼叫,因為之前AutomapperConfiguration.Configure()我沒有看到該呼叫後出現任何內容。這導致一些跟踪語句不再出現。然而重要的是,我看到了我在“工作”中放入的跟踪語句。由於我最終想要解決的是未執行的作業,因此我將該版本的程式碼部署到暫存,但在那裡我只看到了 OnStart() 跟踪和“心跳”跟踪。我不認為這真的有幫助,但也許它會給某人一些想法。

鑑於呼叫了 OnStart() 跟踪,但沒有呼叫 Initialize(),我的猜測是 Initialize() 中的程式碼引用的程序集之一沒有被複製到部署中。請記住,.Net JIT 一次編譯一個方法,並且由於這種行為,顯示 OnStart 跟踪消息是有意義的(因為到目前為止,除了 Windows Azure 和標準 .Net 框架程序集之外幾乎沒有引用) . 但是,當 CLR 轉到 JIT Initialize 方法時,它會嘗試載入幾個第三方程序集(AutoMapper 和 Windsor),這些程序集可能未正確打包,但可能在模擬器執行時被 GACced 或以其他方式在本地可用。

有幾件事可以嘗試:

  1. 從 Visual Studio 手動“打包”您的部署並仔細查看建構輸出。很多時候,VS 會擷取你失去的程序集並告訴你(不幸的是作為警告,而不是錯誤)你失去了一些東西。
  2. 如果您在輸出中看不到任何明顯的內容,請查看 cspkg 文件本身(記住它只是一個包含更多 ZIP 文件的 ZIP 文件)並確保您的應用程序/角色需要的任何引用程序集都在那裡. 或者,連接到 VM 並檢查這些程序集的 approot。
  3. 您可能會在 VM 的事件日誌中找到一個條目,表明您的應用程序無法載入程序集。

通常,此類問題的根本原因是缺少依賴項。在之前的答案中已經有這方面的好建議。

根據您的配置,跟踪日誌每分鐘傳輸一次到 Azure 儲存。如果您的工作程序崩潰,您可能會失去一些最後的跟踪消息。要解決此問題,請嘗試在異常處理程序中添加 Thread.Sleep(TimeSpan.FromMinutes(2)) 以確保將異常日誌刷新到儲存中。

最後,如果一切都失敗了,我建議您嘗試使用 WinDbg 調試您的角色。為您的角色啟用遠端桌面。登錄角色並關閉 IE 安全瀏覽,以便您可以安裝東西。然後從http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=8279下載並安裝適用於 Windows 的調試工具。此軟體包包含整個 Windows SDK,但您可以選擇僅安裝適用於 Windows 的調試工具。

然後執行 WinDbg 並附加到 WaWorkerHost.exe。在 WinDbg 中,執行

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

WinDbg 現在應該在出現 CLR 異常時中斷執行。當它中斷時,執行

!PrintException

查看異常詳細資訊。您可能希望在角色啟動中添加另一個 Thread.Sleep 呼叫,以便在程序退出之前有時間附加調試器。

引用自:https://stackoverflow.com/questions/9410270