Рабочая роль Windows Azure не выходит за пределы первой строки кода

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

Код рабочей роли:

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


person s1mm0t    schedule 23.02.2012    source источник
comment
Правильно ли вы настроили учетную запись хранения для диагностики? Некоторые люди забывают удалить параметр LocalStorage.   -  person Igorek    schedule 23.02.2012
comment
Я так считаю. Я получил одну запись в таблице, которая, кажется, подтверждает эту теорию. Кроме того, изначально я допустил эту ошибку, но VS не собирался создавать пакет с таким оставлением.   -  person s1mm0t    schedule 23.02.2012
comment
Что произойдет, если вы удалите весь «полезный» код из всех методов и оставите только Trace.WriteLine вызовы и развернете его на стадии подготовки? По-прежнему нет сообщений, кроме первого?   -  person Yuriy Guts    schedule 27.02.2012


Ответы (5)


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

Пара вещей, которые стоит попробовать:

  1. Вручную «упакуйте» свое развертывание из Visual Studio и внимательно посмотрите на результат сборки. Часто VS обнаруживает ваши недостающие сборки и сообщает вам (к сожалению, в качестве предупреждения, а не ошибки), что вы чего-то упускаете.
  2. Если вы не видите в выводе ничего очевидного, взгляните на сам файл cspkg (помните, что это просто ZIP-файл с большим количеством ZIP-файлов в нем) и убедитесь, что все сборки, на которые ссылается ваше приложение / роль, находятся там. . Либо подключитесь к виртуальной машине и проверьте одобрение для этих сборок.
  3. Вы можете найти запись в журнале событий виртуальной машины, которая показывает, что вашему приложению не удалось загрузить сборку.
person Doug Rohrer    schedule 28.02.2012
comment
Думаю, это правильный ответ. Убедитесь, что для параметра «Копировать локальное» задано значение «истина» в сборках, на которые имеются ссылки, таких как AutoMapper или Windows. Также проверьте, правильно ли развернуты динамически загруженные типы (из Виндзора). - person Fabio Cozzolino; 29.02.2012
comment
Это неправильный ответ, хотя мне очень жаль, что это было. Я убедился, что все необходимые библиотеки DLL развернуты на виртуальной машине. Кроме того, если бы это была проблема, я бы обязательно увидел вывод исключения в журналы. Как предлагает @sami, я также попытался добавить сон в свой обработчик исключений на случай, если отладка оттуда не была отправлена ​​в хранилище, но безрезультатно. - person s1mm0t; 05.03.2012
comment
Я считаю, что последняя версия SDK также неплохо справляется с подобными проблемами. Когда я впервые попытался создать пакет развертывания, у меня был ряд справочных ошибок, которые мне пришлось исправить, но которые не возникали во время нормальной сборки. - person s1mm0t; 05.03.2012

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

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

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

person Sami    schedule 03.03.2012
comment
Это было отличное предложение, которое, как я думал, поможет. К сожалению, я не вижу исключений. Будет ли это прерываться при исключениях в любом потоке или только в основном потоке? - person s1mm0t; 05.03.2012
comment
Также следовало добавить, что после выполнения команды g он, кажется, работает нормально, и теперь я вижу отладку Heatbeat ..., которую я добавил (см. Обновление исходного вопроса). - person s1mm0t; 05.03.2012
comment
Использование команды! Thread позволяет распечатать текущие потоки. Вы также можете попробовать поставить точку останова где-нибудь в коде задания, чтобы проверить, не сработает ли она. - person Sami; 06.03.2012
comment
Однако отладка с помощью WinDbg - это последнее средство. Вам действительно нужно получить журналы. Вы пробовали добавить CrashDumps.EnableCollection (true); к вашему коду инициализации трассировки? Если рабочий процесс завершается из-за исключения, это должно регистрировать его. - person Sami; 06.03.2012

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

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

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

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

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

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

person s1mm0t    schedule 06.03.2012
comment
Похоже, что теперь рабочий работает в контексте с повышенными правами, теперь я вижу, что вся отладка также отображается в хранилище. Я постараюсь подтвердить это, как только у меня будет время. - person s1mm0t; 06.03.2012

Вы говорите, что у вас есть след

   "WorkerRole.OnStart()"

но не след

   "WorkerRole.Initialize()"

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

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

person kwill    schedule 23.02.2012
comment
Это именно то, что я говорю - я знаю, что это кажется маловероятным, но это все, что я вижу в таблице WADLogs! Я сделаю RDP и проверю процесс WaWorkerHost завтра. - person s1mm0t; 24.02.2012
comment
Я проверил, и, похоже, процесс WaWorkerHost.exe запущен. - person s1mm0t; 24.02.2012
comment
Я бы предложил несколько вещей: 1. Добавьте прослушиватель трассировки файлов в дополнение к DiagnosticMonitorTraceListener. Так вы узнаете, связана ли проблема с вашим приложением или с диагностикой Azure. 2. Используйте что-нибудь вроде DebugView (блог .toddysm.com / 2011/05 /). - person kwill; 24.02.2012
comment
Я попытался добавить прослушиватель трассировки файлов, как вы предложили, но, боюсь, это не помогло. Я обновил вопрос, добавив дополнительную информацию. - person s1mm0t; 27.02.2012

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

Хочу добавить два момента.

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

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

person hocho    schedule 01.03.2012
comment
К сожалению, у @Doug Rohrer нет правильного ответа - см. Комментарий, который я добавил в ответ на его ответ. - person s1mm0t; 05.03.2012
comment
Спасибо за ответ. В качестве последнего вопроса по той же мысли, и, возможно, вы уже это проверили, но возможно ли, что у вас есть DLL в вашем локальном GAC, которая не копируется? - person hocho; 05.03.2012
comment
Единственные ссылки на GAC, которые я вижу, - это стандартные библиотеки .NET, такие как System.dll. Я добавил еще одно обновление к своим исходным вопросам, которое, как мне кажется, доказывает, что проблема не в этом. - person s1mm0t; 05.03.2012