【问题标题】:Windows Azure Worker Role not getting past first line of codeWindows Azure Worker Role 没有通过第一行代码
【发布时间】:2012-03-13 16:39:45
【问题描述】:

我有一个工作角色,在开发中完美运行,但在部署时无法运行。 “不起作用”相当模糊,但这就是我必须继续做的所有事情,因为我没有看到任何错误或任何东西(无论如何在事件日志中 - 也许还有其他地方我可以查看)。我在我的代码中添加了一些跟踪语句,我看到第一个出现了,但其他的都没有。

工人角色代码:

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 在 cmets 部分中所建议的,我已尝试按如下方式添加文件跟踪侦听器:

  <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 的想法不是问题所在。为了希望证明这一点,我已经覆盖了如下所示的运行方法,并且我看到“心跳...”调试出来了。在我看来,诊断功能或至少我配置它的方式都不可靠,这使我无法调查到底为什么我的工作没有运行。

    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 上交叉发布了这个问题。

更新: 正如 cmets 中所建议的,我现在已尝试删除所有“有用”的代码。在开发中,这导致所有调试都被输出。然后我尝试只是删除对AutomapperConfiguration.Configure() 的调用,因为之前我没有看到该调用之后的任何消息。这导致一些跟踪语句不再出现。然而重要的是,我看到了我在“工作”中放入的跟踪语句。由于我最终想要解决的是未运行的作业,因此我将该版本的代码部署到暂存,但在那里我只看到 OnStart() 跟踪和“心跳”跟踪。我不认为这真的有帮助,但也许它会给别人一些想法。

【问题讨论】:

  • 您是否为诊断正确设置了存储帐户?有些人忘记删除 LocalStorage 设置
  • 我相信是的。我在表格中得到一个条目,似乎证明了这一理论。另外,我最初确实犯了这个错误,但是 VS 不会像那样构建包。
  • 如果您从所有方法中删除所有“有用”代码并只留下Trace.WriteLine 调用并将其部署到登台,会发生什么情况?除了第一条消息之外,仍然没有消息?

标签: .net azure system.diagnostics azure-worker-roles


【解决方案1】:

鉴于调用了 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 的事件日志中找到一个条目,表明您的应用程序无法加载程序集。

【讨论】:

  • 我认为这是正确的答案。确保在 AutoMapper 或 Windows 等第三方引用的程序集上将“复制本地”选项设置为 true。还要检查动态加载的类型(来自 Windsor)是否正确部署。
  • 不是正确的答案 - 我真的希望它是。我已经验证了所有需要的 dll 都部署到了虚拟机上。此外,如果这是问题所在,我肯定会在日志中看到异常输出。正如@sami 建议的那样,我还尝试在异常处理程序中添加睡眠,以防从那里进行的调试没有被推送到存储,但无济于事。
  • 我相信最新版本的 SDK 也能很好地解决此类问题。当我第一次尝试创建部署包时,我遇到了一些我必须解决的“参考”错误,这些错误在正常构建期间没有发生。
【解决方案2】:

此类问题的根本原因通常是缺少依赖项。之前的回答中已经有这方面的好建议了。

根据您的配置,跟踪日志每分钟传输一次到 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 调用,以便在进程退出之前有时间附加调试器。

【讨论】:

  • 这是一个很好的建议,我真的认为会有所帮助。不幸的是,我没有看到任何例外。这会中断任何线程或仅主线程上的异常吗?
  • 还应该补充一点,在发出 g 命令后,它似乎运行正常,现在我看到了我添加的“Heatbeat ...”调试(请参阅对原始问题的更新)。跨度>
  • 使用 !threads 命令打印当前线程。您也可以尝试在作业代码中的某处放置一个断点,看看它是否被命中。
  • 使用 WinDbg 调试是最后的手段。您确实需要获取日志。您是否尝试过添加 CrashDumps.EnableCollection(true);到您的跟踪初始化代码?如果工作进程由于异常而退出,这应该记录它。
【解决方案3】:

感谢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。我现在用下面的方法构造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);
    }

这解决了我的主要问题,我现在看到作业按预期执行。

我只能通过在提升的执行上下文中运行辅助角色来解决此问题,以便可以将我的跟踪数据写入文件。我仍然不知道为什么,并且想知道为什么跟踪语句没有正确传输到存储。

【讨论】:

  • 看来,现在工作人员正在提升的上下文中运行,我现在看到所有调试也出现在存储中。我会尽快确认这一点。
【解决方案4】:

你是说你得到了踪迹

   "WorkerRole.OnStart()"

但不是痕迹

   "WorkerRole.Initialize()"

这似乎不太可能,因为两个跟踪语句一个接一个地执行。

您是否尝试过 RDP 到 VM 以查看 WaWorkerHost.exe 进程是否崩溃?

【讨论】:

  • 这正是我要说的——我知道这似乎不太可能,但这就是我在 WADLogs 表中看到的全部内容!明天我会 RDP 并检查 WaWorkerHost 进程。
  • 我现在已经检查过了,WaWorkerHost.exe 进程似乎已经启动了。
  • 我建议以下几点: 1. 除了 DiagnosticMonitorTraceListener 之外,添加一个文件跟踪侦听器。这将告诉您问题是您的应用程序,还是问题是 Azure 诊断。 2. 使用 DebugView (blog.toddysm.com/2011/05/…) 之类的东西。
  • 我已尝试按照您的建议添加文件跟踪侦听器,但恐怕这并没有真正帮助。我已经用更多信息更新了这个问题。
【解决方案5】:

我相信 Doug Rohrer 的答案是正确的。您很有可能在项目中缺少 DLL,这可以通过检查包来验证。请注意,如果您使用的是 1.6 SDK 之前的版本,则需要在未加密的情况下创建包。

我想补充两点。

  1. 将“复制本地”设置为 true,在某些情况下,仅当 项目文件是手动编辑的,并明确给出了程序集的完整路径。 (当程序集也存在于本地计算机的 GAC 中时,会发生这种情况)。

  2. 如果引用的依赖项位于程序集中,则 由 Azure 角色程序集引用,依赖项 没有得到副本。在这种情况下,这些依赖项也需要 被添加到角色程序集中,即使它们不被它使用。 (这有点难以置信,但我确实遇到了这个问题)。

【讨论】:

  • 不幸的是,@Doug Rohrer 没有正确的答案 - 请参阅我为回应他的回答而添加的评论。
  • 感谢您的反馈。作为同一思路的最后一个问题,也许您已经验证了这一点,但是您的本地 GAC 中是否有一个 DLL 而不是被复制?
  • 我能看到的对 GAC 的唯一引用是标准 .NET 库,例如 System.dll。不幸的是,我对我的原始问题添加了另一个更新,我认为这证明这不是问题。
猜你喜欢
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-24
  • 2015-03-17
  • 2017-09-06
  • 2014-11-30
相关资源
最近更新 更多