Исключение выходит из рабочего процесса, несмотря на активность TryCatch - PullRequest
1 голос
/ 22 сентября 2010

У меня есть рабочий процесс внутри службы Windows, который представляет собой цикл, который периодически выполняет работу. Работа выполняется в рамках действия TryCatch. Свойство Try является действием TransactionScope, которое охватывает некоторые пользовательские действия, которые читают и обновляют базу данных. Когда транзакция завершится неудачно, я ожидаю, что любое исключение, вызвавшее это, будет обнаружено TryCatch. Тем не менее, мой рабочий процесс прерывается. Рабочий процесс у меня следующий:

var wf = new While(true)
{
    Body = new Sequence
    {
        Activities =
        {
            new TryCatch
            {
                Try = new TransactionScope
                {
                    IsolationLevel = IsolationLevel.ReadCommitted,
                    Body = new Sequence
                    {
                        Activities = { ..custom database activities.. }
                    },
                    AbortInstanceOnTransactionFailure = false
                },
                Catches =
                {
                    new Catch<Exception>
                    {
                        Action = new ActivityAction<Exception>
                        {
                            Argument = exception,
                            Handler = ..log error..
                        }
                    }
                }
            },
            new Delay { Duration = new InArgument<TimeSpan>(duration) }
        }
    },
}

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

System.OperationCanceledException: ошибка обработки текущего рабочего элемента привела к прерыванию рабочего процесса.

Внутреннее исключение:

System.Transactions.TransactionException: операция недопустима для состояния транзакции.

Это имеет смысл, потому что я только что выключил базу данных. Однако, почему это исключение не обрабатывается моей TryCatch активностью?

EDIT 1 : некоторая дополнительная информация. Я запускаю рабочий процесс, используя класс WorkflowApplication. Чтобы лучше понять, что происходит, я указал свойства Aborted и OnUnhandledException. Когда возникает исключение, оно переходит непосредственно к Aborted, а OnUnhandledException пропускается (хотя это явно необработанное исключение).

РЕДАКТИРОВАТЬ 2 : я включил журнал отладки, и это дает некоторую дополнительную информацию. «Пользовательские действия с базой данных» успешно завершены. Первая запись в журнале событий, указывающая, что что-то не так, - это подробное сообщение уровня: Транзакция времени выполнения завершила с состоянием «Прервано» . Затем я вижу информационное сообщение: WorkflowInstance Id: 'dbd1ba5c-2d8a-428c-970d-21215d7e06d9' E2E Activity (не уверен, что это значит). И информационное сообщение после этого: Действие 'System.Activities.Statements.TransactionScope', DisplayName: «Транзакция для запуска немедленно проверяет», InstanceId: «389» завершено в состоянии «Ошибка» .

После этого сообщения я вижу, что каждый родитель (включая действие TryCatch) завершает работу в состоянии «Сбой», заканчивая прерыванием моего рабочего процесса.

РЕДАКТИРОВАТЬ 3 : Для ясности, все работает, как и ожидалось, когда возникает исключение в любой из «пользовательских операций с базой данных». Обнаружено исключение, и рабочий процесс продолжается. Это происходит только тогда, когда транзакция не может быть зафиксирована в конце TransactionScope. Смотрите следующую трассировку стека, которая регистрируется из обратного вызова Aborted:

at System.Transactions.TransactionStateInDoubt.Rollback(InternalTransaction tx, Exception e)
at System.Transactions.Transaction.Rollback(Exception e)
at System.Activities.Runtime.ActivityExecutor.CompleteTransactionWorkItem.HandleException(Exception exception)

Если вы будете следовать вызовам из TransactionScope.OnCompletion(...), в итоге вы получите класс ActivityExecutor из стековой трассировки.

Ответы [ 2 ]

5 голосов
/ 27 сентября 2010

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

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

Много лет назад, когда я был руководителем программы в команде COM +, я изучал эту проблему, потому что часто люди хотят, чтобы транзакционный компонент (или рабочий процесс) мог реагировать на прерывание транзакции.

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

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

2 голосов
/ 28 сентября 2010

Так что просто добавлю к ответу Рона. Единственный вариант здесь - добавить SqlWorkflowInstanceStore и удалить действие Persist непосредственно перед TransactionScope. Когда транзакция прерывается, весь рабочий процесс будет прерван, но сохраненное в прошлом состояние все еще будет находиться в базе данных постоянства, и рабочий процесс можно будет перезапустить из этого ранее сохраненного состояния и выполнить транзакцию снова.

...