Как защитить пулы приложений от исключений сериализации сеанса? - PullRequest
7 голосов
/ 21 июня 2010

Мы используем поставщика сеанса вне процесса ( ScaleOut ) для приложения ASP.NET, и мы заметили, что , когда объект, который неправильно настроен длядесериализация непреднамеренно переходит в сессию, это в конечном итоге приведет к завершению всего процесса .

Воспроизведение и обработка этого сценария - вот где он становится еще более интересным.

Исключение, которое завершает процесс, возникает в AnyStaObjectsInSessionState , реализация которого довольно проста:

internal static bool AnyStaObjectsInSessionState(HttpSessionState session)
{
    if (session != null)
    {
        int count = session.Count;
        for (int i = 0; i < count; i++)
        {
            object obj2 = session[i];
            if (((obj2 != null) && (obj2.GetType().FullName == "System.__ComObject"))
                && (UnsafeNativeMethods.AspCompatIsApartmentComponent(obj2) != 0))
            {
                return true;
            }
        }
    }
    return false;
}

Вот трассировка стека, которая показывает, как исключения здесь завершают процесс:

An unhandled exception occurred and the process was terminated.

Application ID: /LM/W3SVC/1/ROOT

Process ID: 4208

Exception: System.Runtime.Serialization.SerializationException

Message: The constructor to deserialize an object of type 'Lucene.Net.QueryParsers.ParseException' was not found.

StackTrace:    at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
   at System.Runtime.Serialization.ObjectManager.DoFixups()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Web.Util.AltSerialization.ReadValueFromStream(BinaryReader reader)
   at System.Web.SessionState.SessionStateItemCollection.ReadValueFromStreamWithAssert()
   at System.Web.SessionState.SessionStateItemCollection.DeserializeItem(String name, Boolean check)
   at System.Web.SessionState.SessionStateItemCollection.DeserializeItem(Int32 index)
   at System.Web.SessionState.SessionStateItemCollection.get_Item(Int32 index)
   at System.Web.SessionState.HttpSessionStateContainer.get_Item(Int32 index)
   at System.Web.Util.AspCompatApplicationStep.AnyStaObjectsInSessionState(HttpSessionState session)
   at System.Web.HttpApplicationFactory.FireSessionOnEnd(HttpSessionState session, Object eventSource, EventArgs eventArgs)
   at System.Web.SessionState.SessionOnEndTargetWorkItem.RaiseOnEndCallback()
   at System.Web.Util.WorkItem.CallCallbackWithAssert(WorkItemCallback callback)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

InnerException: System.Runtime.Serialization.SerializationException

Message: The constructor to deserialize an object of type 'Lucene.Net.QueryParsers.ParseException' was not found.

StackTrace:    at System.Runtime.Serialization.ObjectManager.GetConstructor(Type t, Type[] ctorParams)
   at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)

Мы хотели бы понять две вещи:

  1. Когда это FireSessionOnEnd срабатывает для стороннего поставщика и, что более важно, как мы можем имитировать это в среде разработки, которая не находится под нагрузкой?Я экспериментировал с уменьшенными тайм-аутами сеанса (установленными в минуту), вручную вызывая Abandon () и вручную вызывая GC.Collect (), но все безрезультатно.

  2. Можем ли мы перехватить ошибки, которые происходят на этом этапе, чтобы защитить пул приложений?Возникающие здесь исключения регистрируются как w / Source = ASP.NET 2.0.50727.0 и не достигают обработчиков ошибок приложения в global.asax.Что мы можем сделать, чтобы защититься от этого сценария, даже после применения соответствующих сдержек и противовесов к объектам, привязанным к сеансу?

Буду признателен за любые идеи.

Ответы [ 3 ]

3 голосов
/ 30 июня 2010

Мы смогли решить эту проблему с помощью технической поддержки SOSS - они были чрезвычайно полезны - вот подробности:

  • По истечении сеанса SOSS вызывает событие истечения в своих клиентских библиотеках.которые, в свою очередь, ответственны за запуск Session_End в Global.asax ( NB: ScaleOut балансирует события истечения срока действия нагрузки для клиентов, поэтому веб-сервер, создавший сеанс, может не получать событие истечения срока действия - это критически важно дляпытаясь воспроизвести эти проблемы).
  • Поскольку это происходит вне контекста запроса, исключение не обрабатывается и убивает пул приложений;
  • Это крайне необычный сценарий, но он, тем не менее, будет рассмотрен в будущих выпусках обслуживания;
  • Исправлены следующие действия:

    1. Исправлен тип System.Exception (получаемый сериализацией, но не сериализуемый);

    2. Удаление событий Session_End в Global.asax или отключение событий истечения срока действия ( max_event_retries , установленный в 0 в soss_params.txt);

    3. В этих сценариях пользователь может встретить SerializationException по одному из своих запросов, что означает, что он достигает Application_Error ;здесь вы можете очистить сеансовые ключи (должны очистить все из них) или полностью отказаться от сеанса;

    4. Подпишитесь на AppDomain.UnhandledException , чтобы получать уведомления о необработанных исключениях, если они произойдут (здесь не нужно обращаться, только ведение журнала);их также можно отключить с помощью legacyUnhandledExceptionPolicy (не рекомендуется);

1 голос
/ 30 июня 2010

Можем ли мы отловить ошибки, которые происходят при этом шаг для защиты пула приложений? Возникшие здесь исключения регистрируются с Источник = ASP.NET 2.0.50727.0 и не добраться до обработчиков ошибок приложения в global.asax. Что мы можем сделать, чтобы защититься от этого сценария, даже после соответствующих проверок и противовесов применяются к объектам, привязанным к сеансу?

Я не знаю, сработает ли , это , но вы можете дать ему шанс

0 голосов
/ 27 января 2016

Я исправил это, просто полностью удалив методы SessionEnd. Недостаточно удалить содержимое методов, так как Asp.net ищет существование метода, используя отражение, а затем запускает нарушающий код.

...