Рабочая роль Windows Azure не проходит первую строку кода - PullRequest
10 голосов
/ 23 февраля 2012

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

Код 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 Code:

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().

Обновление: I должен что-то настроено неправильнос моей диагностикой.Я думал, что вижу, что моя отладка правильно выходит при локальной отладке, но оказывается, что нет.Я вижу все в окне вывода, но я не вижу все в таблице хранения.Я вижу следующие записи в разработке:

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

Ответы [ 5 ]

5 голосов
/ 28 февраля 2012

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

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

  1. Вручную «упакуйте» свое развертывание из Visual Studio и внимательно посмотрите на результаты сборки.Много раз VS обнаружит ваши недостающие сборки и скажет вам (к сожалению, как предупреждение, а не ошибка), что вы что-то упустили.
  2. Если вы не видите ничего в выводе, которое выглядит очевидным, сделайтепосмотрите на сам файл cspkg (помните, что это всего лишь ZIP-файл с большим количеством ZIP-файлов в нем) и убедитесь, что там есть все ссылки на сборки, необходимые для вашего приложения / роли.Кроме того, подключитесь к виртуальной машине и проверьте подходящие для этих сборок.
  3. Возможно, вы сможете найти запись в журнале событий виртуальной машины, которая показывает, что вашему приложению не удалось загрузить сборку.
3 голосов
/ 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 при запуске вашей роли, чтобы дать вам время подключить отладчик до завершения процесса.

1 голос
/ 06 марта 2012

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

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

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

Корнем роли при подготовке является 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);
    }

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

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

0 голосов
/ 01 марта 2012

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

Я хотел бы добавить две точки.

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

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

0 голосов
/ 24 февраля 2012

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

   "WorkerRole.OnStart()"

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

   "WorkerRole.Initialize()"

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...