2012-02-23 67 views
10

我有一個工作角色,可以在開發中完美工作,但部署時不起作用。 「不起作用」是相當含糊的,但這就是我所要做的,因爲我沒有看到任何錯誤或任何事情(無論如何,在事件日誌中 - 也許有其他地方我可以看)。我在代碼中添加了一些跟蹤語句,我看到第一個出來,但沒有其他人。Windows Azure Worker角色沒有通過代碼的第一行

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 
} 

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> 

一旦工人爲S tarted,如果我看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 forum

更新:正如評論中所建議的,我現在已經嘗試刪除所有'有用'的代碼。在開發中,這導致了所有的調試輸出。然後我嘗試只是刪除電話AutomapperConfiguration.Configure(),因爲以前我沒有看到任何後出來的電話。這導致一些跟蹤陳述不再出現。但是,重要的是,我看到了我在「工作」中提出的跟蹤陳述。由於最終要解決的是未運行的作業,因此我將該版本的代碼部署到了暫存中,但在那裏我只看到OnStart()跟蹤和「心跳」跟蹤。我不認爲這真的有幫助,但也許它會給人一些想法。

+0

您是否正確設置了您的存儲帳戶以進行診斷?有些人忘記刪除LocalStorage設置 – Igorek 2012-02-23 17:48:21

+0

我相信如此。我在表格中看到一個似乎證明理論的條目。另外,我最初確實犯了這個錯誤,但是VS不會像這樣創建它。 – s1mm0t 2012-02-23 17:53:34

+1

如果您從所有方法中刪除所有「有用」代碼,並且只保留「Trace.WriteLine」調用並將其部署到分段中,會發生什麼情況?除了第一個消息還沒有消息? – 2012-02-27 18:34:06

回答

1

感謝MSDN forum的回答,我已經能夠排除故障並解決我的問題。

爲什麼我的作業沒有被執行,是由於線下的原因:

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

上分期中的作用根是E :. Path.Combine()有一個模糊的實現,您可以在this SO answer中閱讀更多信息。這意味着Castle正在按照我的預期搜索E:approot中的程序集,而不是E:\ approot。我正在用下面的方法構建批准路徑:

private string GetAppRoot() 
    { 
     string root = Environment.GetEnvironmentVariable(Constants.RoleRoot); 

     if (root.EndsWith(Path.VolumeSeparatorChar.ToString())) 
      root += Path.DirectorySeparatorChar; 

     return Path.Combine(root, Constants.AppRoot); 
    } 

這已經解決了我的主要問題,現在我看到作業按預期執行。

我只能通過在提升的執行上下文中運行輔助角色來解決此問題,以便可以將我的跟蹤數據寫入文件。我仍然不知道爲什麼,並希望聽到任何想法,爲什麼跟蹤語句沒有正確傳輸到存儲。

+0

看來,現在工作人員正在提升的環境中運行,現在我看到所有的調試都出現在存儲器中。我會盡快確認這一點。 – s1mm0t 2012-03-06 15:53:03

0

你是說,你得到的跟蹤

"WorkerRole.OnStart()" 

但不跟蹤

"WorkerRole.Initialize()" 

這似乎不大可能,因爲這兩個跟蹤語句後,其他執行一個正確的。

您是否嘗試過RDP到虛擬機以查看WaWorkerHost.exe進程是否崩潰?

+0

這正是我所說的 - 我知道這似乎不太可能,但這是我在WADLogs表中看到的所有內容!我將RDP和明天檢查WaWorkerHost進程。 – s1mm0t 2012-02-23 22:32:25

+0

我現在已經檢查並且WaWorkerHost.exe進程似乎已經啓動。 – s1mm0t 2012-02-24 10:12:15

+0

我會建議幾件事: 1.除了DiagnosticMonitorTraceListener之外,還要添加文件跟蹤偵聽器。這會告訴你問題是你的應用,還是問題是Azure診斷。 2.使用類似DebugView(http://blog.toddysm.com/2011/05/using-debugview-to-troubleshoot-windows-azure-deployments.html)。 – kwill 2012-02-24 16:50:50

5

考慮到OnStart()跟蹤被調用,但不是Initialize(),我的猜測是Initialize()中的代碼所引用的程序集中的一個未被複制到部署。請記住,.Net JIT每次編譯一個方法,由於這種行爲,OnStart跟蹤消息顯示出來是有意義的(因爲除此之外引用的Windows Azure和標準.Net框架程序集幾乎沒有) 。但是,當CLR轉到JIT Initialize方法時,它會嘗試加載幾個第三方程序集(AutoMapper和Windsor),這些程序集可能無法正確打包,但在仿真程序運行時可能是GACced或本地可用的。

幾件事情嘗試:

  1. 手動「包」您從Visual Studio部署,並採取在構建輸出仔細一看。很多時候,VS會抓住你想要的東西,並告訴你(不幸的是,作爲一個警告,而不是錯誤),你錯過了一些東西。
  2. 如果在輸出中看不到任何明顯的內容,請查看cspkg文件本身(請記住它只是一個包含更多ZIP文件的ZIP文件),並確保您的應用程序/角色需要的任何引用程序集在那裏。或者,連接到VM並檢查這些程序集的批准。
  3. 您可能能夠在虛擬機的事件日誌中找到一個條目,其中顯示您的應用程序無法加載程序集。
+0

我認爲這是正確的答案。確保在第三部分引用的組件(如AutoMapper或Windows)上將「複製本地」選項設置爲true。同時檢查(來自Windsor的)裝載的類型是否正確部署。 – 2012-02-29 11:02:04

+0

這是*不是正確的答案 - 我真的希望它是。我已經驗證了所有需要的dll都部署到虛擬機。此外,如果這是問題,我一定會看到輸出到日誌的異常。正如@sami所示,我也嘗試在我的異常處理程序中添加一個睡眠,以防從那裏調試沒有被推送到存儲,但無濟於事。 – s1mm0t 2012-03-05 15:03:52

+0

我相信最新版本的SDK在挑選這樣的問題方面也相當不錯。當我第一次嘗試創建部署包時,我遇到了許多「參考」錯誤,我必須解決這些錯誤,這些錯誤在正常構建過程中不會發生。 – s1mm0t 2012-03-05 15:06:45

0

我相信Doug Rohrer有正確的答案。您很可能會丟失項目中可以通過檢查軟件包進行驗證的DLL。請注意,如果您使用的是早期版本的1.6 SDK,則需要以未加密方式創建軟件包。

我想補充兩點。

  1. 設置「複製本地」設置爲true,在某些情況下,如果 項目文件手動編輯並明確給出組件的完整路徑纔有效。 (當組件也存在於本地機器的GAC中時,會發生這種情況)。

  2. 如果引用的依賴項位於由Azure角色程序集引用的 引用的程序集中,則依賴關係確實不會獲取副本。在這種情況下,這些依賴關係也需要被添加到角色程序集中,即使它們沒有被它使用。 (這是很難相信的,但我碰到過這個問題)。

+0

不幸的@Doug Rohrer沒有正確的答案 - 請參閱我在回答他的回答時添加的評論。 – s1mm0t 2012-03-05 15:05:17

+0

感謝您的反饋。作爲同一思路的最後一個問題,也許您已經驗證了這一點,但是您可能在本地GAC中有一個DLL,而不是被複制過來? – hocho 2012-03-05 16:11:17

+0

我可以看到的唯一對GAC的引用是標準的.NET庫,如System.dll。我已經添加了另一個更新到我原來的問題,我認爲這不是問題,不幸的是。 – s1mm0t 2012-03-05 16:48:28

3

往往不是這樣的問題的根本原因是缺少依賴關係。在以前的答案中,這方面已經有很好的建議。

根據您的配置,跟蹤日誌每分鐘轉移到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 

時,有一個CLR例外的WinDbg現在應該中斷執行。當它打破時,執行

!PrintException 

查看異常詳細信息。您可能需要在角色啓動中添加另一個Thread.Sleep調用,以便在進程退出前給您時間來附加調試器。

+0

這是一個偉大的建議,我真的認爲會有所幫助。不幸的是我沒有看到任何例外。這會打破任何線程或主線程上的異常嗎? – s1mm0t 2012-03-05 17:02:42

+0

還應該補充一點,在發出g命令後,它似乎正常運行,現在我看到了我添加的「Heatbeat ...」調試(請參閱原始問題的更新)。 – s1mm0t 2012-03-05 17:05:10

+0

使用!threads命令打印當前線程。您也可以嘗試在作業代碼中的某個地方放置斷點,以查看它是否被擊中。 – Sami 2012-03-06 08:17:08