2012-02-23 65 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

相关问题