Роль рабочего сервера Windows Azure, не прошедшая первую строку кода

У меня есть рабочая роль, которая отлично работает в разработке, но не работает при развертывании. "Не работает" довольно расплывчато, но на самом деле все, что я должен продолжать, поскольку я не вижу никаких ошибок или чего-либо еще (в любом случае журнал событий - возможно, где-то еще я могу посмотреть). Я добавил некоторые инструкции к моему коду, и я вижу, что первый вышел, но никто из других.

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

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>

Как только рабочий запустится, если я посмотрю в 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() и трассировку "сердцебиение". Я не думаю, что это действительно помогает, но, возможно, это даст кому-то некоторые идеи.

Ответ 1

Благодаря ответу на форуме MSDN, я смог устранить и устранить свою проблему.

Причина, по которой мои задания не выполнялись, была вызвана следующей строкой:

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

Роль root при постановке - E:. Path.Combine() имеет неясную реализацию, о которой вы можете узнать больше в этом SO-ответе. Это означало, что замок искал сборки в 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);
    }

Это решило мою основную проблему, и теперь я вижу, что задания выполняются так, как ожидалось.

Я смог устранить эту проблему, выполнив рабочую роль в расширенном контексте выполнения, чтобы мои данные трассировки могли быть записаны в файл. Я до сих пор не знаю, почему, и хотел бы услышать какие-либо идеи, почему инструкции трассировки не были правильно переданы на хранение.

Ответ 2

Учитывая, что вызывается трассировка OnStart(), но не Initialize(), я предполагаю, что одна из сборок, на которые ссылается код в Initialize(), не копируется в развертывание. Помните, что .Net JIT-компилирует по одному методу за раз, и из-за этого поведения было бы разумно, что появляется сообщение о трассировке OnStart (так как там немного больше, чем Windows Azure и стандартные сборки .NET-структуры, на которые ссылаются до этой точки), Однако, когда CLR переходит на JIT метод Initialize, он затем пытается загрузить несколько сторонних сборок (AutoMapper и Windsor), которые могут быть неправильно упакованы, но могут быть GACced или иным образом доступны локально при запуске эмулятора.

Несколько вещей, чтобы попробовать:

  • Вручную "Пакет" вашего развертывания из Visual Studio и внимательно изучите вывод сборки. Много раз VS будет улавливать ваши недостающие сборки и сообщать вам (к сожалению, как предупреждение, а не об ошибке), что вам что-то не хватает.
  • Если вы ничего не видите на выходе, который выглядит очевиден, посмотрите сам файл cspkg (помните, что это только ZIP файл с большим количеством ZIP файлов) и убедитесь, что любые ссылочные сборки, которые необходимы вашему приложению/роли находятся там. В качестве альтернативы подключитесь к виртуальной машине и проверьте соответствие для этих сборок.
  • Вы можете найти запись в журнале событий виртуальной машины, которая показывает, что приложение не смогло загрузить сборку.

Ответ 3

Чаще всего, основной причиной таких проблем является отсутствие зависимостей. В предыдущих ответах уже есть хорошие предложения по этому вопросу.

Журналы трассировки передаются на хранение Azure один раз в минуту в соответствии с вашей конфигурацией. Если ваш рабочий процесс выйдет из строя, вы можете потерять некоторые из последних сообщений трассировки. Чтобы обойти это, попробуйте добавить в обработчики исключений Thread.Sleep(TimeSpan.FromMinutes(2)), чтобы убедиться, что журнал исключений сброшен на хранение.

Наконец, если все остальное не удается, я предлагаю вам попробовать отладить свою роль с помощью WinDbg. Включите удаленный рабочий стол для своей роли. Войдите в эту роль и отключите безопасный просмотр IE, чтобы вы могли установить материал. Затем загрузите и установите средства отладки для Windows из http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=8279. Этот пакет содержит весь SDK Windows, но вы можете выбрать установку инструментов для отладки только для 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 в своем запуске роли, чтобы дать вам время для присоединения отладчика до выхода процесса.

Ответ 4

Вы говорите, что получаете трассировку

   "WorkerRole.OnStart()"

но не трассировка

   "WorkerRole.Initialize()"

Это кажется маловероятным, поскольку два оператора трассировки выполняются один за другим.

Вы пытались выполнить RDP для виртуальной машины, чтобы узнать, сбой процесса WaWorkerHost.exe?

Ответ 5

Я считаю, что Дуг Рорер имеет верный ответ. Существует высокая вероятность того, что у вас недостает DLL в проекте, который может быть проверен путем изучения этого пакета. Имейте в виду, что пакет необходимо создать незашифрованным, если вы используете ранее версию 1.6 SDK.

Я хотел бы добавить два пункта.

  • Настройка "Копировать локальную" на true, в некоторых случаях работает только в том случае, если файл проекта редактируется вручную и явно задается полный путь сборки. (Это происходит, когда сборка также присутствует в GAC локальной машины).

  • Если ссылки, на которые ссылаются, находятся в сборке, которая находится в обменивались ссылками с помощью сборки роли Azure, зависимости не получить копии. В этом случае эти зависимости также должны быть добавлены в сборку ролей, даже если они не используются им. (Это сложно поверить, но я столкнулся с этой проблемой).