AppDomain, обработка исключений - PullRequest
15 голосов
/ 16 августа 2011

Я разрабатываю большое приложение, которое состоит из множества плагинов / приложений меньшего размера.

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

Во время поиска решения я могу найти магическое слово AppDomain и указать:

"Использование доменов приложений для изоляции задач, которые могут привести к сбою процесса. Если состояние домена приложения, выполняющего задачу, становится нестабильным, домен приложения можно выгрузить, не влияя на процесс. Это важно, когда процесс должен выполняться в течение длительного времени.без перезапуска. Вы также можете использовать домены приложений для изоляции задач, которые не должны обмениваться данными. "

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

Итак, я создал приложение, которое запускается, ищет все .dll в своей папке.Проверяет, состоит ли dll из плагина.Создает новый AppDomain для этого плагина, и как только все будет загружено, он запустит каждый плагин.(Где каждый плагин может состоять из нескольких потоков, счастливо сосуществующих рядом с каждым другим).

Поэтому я также добавил там тайм-аут, который срабатывает через 5 секунд, чтобы выдать новое Exception ();Добавлено событие UnhandledException в AppDomain для его обработки.Но он поймал его, и после кэтинга все равно «рухнул» весь процесс, включая все дополнительные дочерние домены.

Но в цитате четко указано «выделить задачи, которые« могут »остановить процесс».».Так я что-то упускаю из жизни?Мой взгляд на цитату неправильный?

Ответы [ 4 ]

16 голосов
/ 16 августа 2011

Начиная с .NET 2.0 необработанные исключения завершают процесс . От AppDomain.UnhandledException документация о событии:

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

То же самое относится к AppDomain.FirstChanceException :

Это событие является только уведомлением . Обработка этого события не обрабатывает исключение или каким-либо образом повлиять на последующую обработку исключений.

Вам нужно подумать о том, как вы будете обрабатывать исключения, так же, как вы будете делать это в обычном приложении. Просто использование доменов приложений не поможет. Если исключение не было обработано в данном AppDomain, оно будет переброшено при вызове AppDomain до тех пор, пока оно не будет обработано или не завершит процесс. Прекрасно обрабатывать некоторые исключения и не позволять им прервать ваш процесс.

AppDomain - логический контейнер для сборок и памяти (не для потоков). Изоляция для AppDomain подразумевает:

  • Объекты, созданные в домене A, не могут быть доступны напрямую доменом B (без маршалинга). Это позволяет выгружать домен A, не затрагивая ничего в домене B. Эти объекты будут автоматически удаляться при выгрузке «собственного» домена.

  • Сборки могут автоматически выгружаться через AppDomain. Это единственный способ выгрузить управляемый dll из процесса. Это полезно для горячей замены DLL.

  • Разрешения и настройки безопасности AppDomain могут быть изолированы от других доменов AppDomain. Это может быть полезно при загрузке ненадежного стороннего кода. Он также позволяет вам переопределить способ загрузки сборок (привязка версии, теневое копирование и т. Д.).

Наиболее распространенные причины использования AppDomain - это когда вы запускаете ненадежный сторонний код. Или у вас есть неуправляемый код и вы хотите разместить CLR или вам нужна горячая замена dll. Я думаю, что в CLR-хостинге вы можете спасти свой процесс от сбоя, когда сторонний код генерирует необработанное исключение.

Также вместо того, чтобы развернуть собственную инфраструктуру, вы можете посмотреть System.Addin или MEF .

7 голосов
/ 16 августа 2011

Есть две проблемы с необработанным исключением. AppDomain решает только один из них. Вы пытаетесь разобраться с другим.

Сначала хорошие новости. Когда вы обрабатываете исключение, вы должны восстановить состояние программы, как если бы исключение никогда не происходило. Все должно быть перемотано до состояния, предшествующего кодированию. Обычно у вас есть куча предложений catch и finally, которые отменяют мутации состояния, выполняемые кодом. Ничего очень простого, конечно. Но совершенно невозможно, если исключение не обработано. Вы не знаете точно, что мутировало и как его восстановить. AppDomain решает эту очень сложную проблему с aplomb. Вы выгружаете его, и все, что осталось, просто исчезло Больше нет кучи мусора, больше нет кучи загрузчика (статика). Вся энчилада возвращается в состояние, равное до создания вами домена приложения.

Отлично. Но есть и другая проблема, с которой довольно сложно справиться. Вашу программу попросили выполнить работу. Нить отправилась на эту работу. Но он перенес сердечный приступ. Большая проблема номер один: нить мертва. Это довольно плохая новость, если в вашей программе для начала был только один поток. Нет потока, программа завершается. Приятно, что AppDomain выгружен первым, но на самом деле это не имеет значения, он все равно выгружен.

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

Как вы решаете это?

Есть только несколько выбранных сценариев, где это приемлемо. Серверные сценарии. Кто-то просит, чтобы он что-то сделал, сервер сообщает, что "не мог этого сделать, пожалуйста, свяжитесь с системным администратором". Как работают ASP.NET и SQL Server. Они используют домены приложений для поддержания стабильности сервера. И есть системные администраторы для решения проблем. Вам нужно будет создать такую ​​систему поддержки, чтобы AppDomains работал на вас.

5 голосов
/ 16 января 2013

Просто добавив некоторую дополнительную информацию по этому вопросу для тех, кто рассматривает (бывал там сам) использование доменов приложений в основном для обеспечения стабильности приложения:

Несколько лет назад команда System.AddIn опубликовала очень интересную запись в блоге. Использование изоляции AppDomain для обнаружения сбоев надстроек .

Это объясняет, что только внешние надстройки могут гарантировать стабильность хоста. Более конкретно:

Начиная с CLR v2.0, необработанные исключения для дочерних потоков будут теперь привести к срыву всего процесса и, следовательно, это невозможно для хоста, чтобы полностью оправиться от этого.

Так что они предлагают подписаться на AppDomain.UnhandledException и, прежде чем ваше приложение завершится сбоем, где-то сохраните (журнал, база данных и т. Д.) Информацию о том, кто вызвал это исключение. Затем в следующий раз ваше приложение начнет использовать эту информацию для защиты вашего приложения. Возможно, вы не загружаете надстройку или информируете пользователя и позволяете ему / ей решать. (Приложения Microsoft Office следовали этому подходу и отключили плагины, которые вызывали сбой в работе хоста. Затем вам нужно было повторно включить их самостоятельно.)

Они также опубликовали еще одну запись в блоге, в которой показано, как это сделать, даже в тех случаях, когда хост работает на другом хосте (IIS, WAS и т. Д.). Подробнее о регистрации необработанных исключений из управляемых надстроек .

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

3 голосов
/ 16 августа 2011

AppDomain более часто используется для возможности выгрузки сборок (например, по вашему предложению) и для контроля параметров запуска, таких как уровни доступа .NET, конфигурации и т. Д. Если вы действительно хотите «изоляцию», то лучшим вариантом всегда будет рабочий процесс.;однако, это намного больше работы.

Я делаю это довольно много в нескольких проектах.Просто, чтобы дать общее представление, мы используем Google ProtoBuffers ( порт Джона Скита ) поверх управляемой библиотеки Windows LRPC для большинства сообщений.Для управления рабочими процессами мы в значительной степени полагаемся на именованные события, я недавно опубликовал здесь библиотеку межпроцессных событий *1010* именно для этой цели.

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