Какие шаги я могу предпринять, чтобы сделать рабочий процесс устойчивым к исключениям - PullRequest
1 голос
/ 10 ноября 2011

Я очень новичок в разработке Workflow Foundation и беспокоюсь, что открываю серьезные дыры в обработке наших бизнес-процессов, неправильно обрабатывая исключения приложений / баз данных в пользовательских действиях.

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

Ответы [ 2 ]

4 голосов
/ 10 ноября 2011

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


Первый вариант (во время выполнения операции / рабочего процесса):

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

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

Предположим, у вас есть пользовательское действие, которое что-то сохраняет в БД:

public sealed PersistIntegerToDb : CodeActivity
{
    public InArgument<int> ValueToPersist { get; set; }

    protected override void Execute(CodeActivityMetadata metadata)
    {
        try
        {
            // persist
        }
        catch(SqlException exception) 
        {
            // re throws the SqlException

            throw new SqlException("'ValueToPersist' wasn't persisted.", exception);
        }
    }
}

Затем в вашем коде или в конструкторе вы можете выполнить действие TryCatch , чтобы отловить эту ошибку и обработать ее так, как вы хотите:

var workflow = new TryCatch
{
    Try = new PersistIntegerToDb
    {
        ValueToPersist = 10
    },
    Catches =
    {
        new Catch<SqlException>
        {
            Action = new ActivityAction<SqlException>
            {
                Handler = new WriteLine 
                {
                     Text = "An error occurred and the value wasn't saved! Anyway workflow will continue..."
                }
            }
        }
    }
}

Или вы можете прекратить его, используя TerminateWorkflow .


Второй вариант (во время разработки):

Хорошо, но вы можете утверждать, что клиент не знает, что он должен обрабатывать эти случаи . В этом случае, и это вариант удобства использования, который вы могли бы рассмотреть, вместо того, чтобы делать доступным PersistIntegerToDb в конструкторе, вы можете предоставить действие, уже окруженное обработчиками исключений, для обработки, через IActivityTemplateFactory :

public sealed PersistIntegerToDbFactory : IActivityTemplateFactory
{
    public Activity Create(DependencyObject target)
    {
        return new TryCatch
        {
            Try = new PersistIntegerToDb
            {
                ValueToPersist = 10
            },
            Catches =
            {
                new Catch<SqlException>
                {
                }
            }
        };
    }
}

Теперь вы просто добавляете PersistIntegerToDbFactory, как если бы это было обычное действие:

new ToolboxItemWrapper(typeof(PersistIntegerToDbFactory), null, "Persist Integer");

Третий вариант (во время проверки):

Никогда не забывайте проверить рабочий процесс перед выполнением!

var validationResults =
    ActivityValidationServices.Validate(workflow);

foreach(var error in validationResults.Errors)
{
    Console.WriteLine(string.Format(
        "Validation error '{0}', generated on activity '{1}' in the property named {2}",
        error.Message,
        error.Source.DisplayName,
        error.PropertyName));
}

Четвертый вариант (во время выполнения приложения):

Вы можете обработать все необработанные исключения, которые могут произойти во время выполнения, используя событие OnUnhandledException:

var wfApp = new WorkflowApplication(activity);

wfApp.OnUnhandledException += 
    delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
    {
        if (e.UnhandledException is SqlException)
        {
            Console.WriteLine("Some data wasn't properly persited.");
        }
        else 
        {
            Console.WriteLine("Unknown error: " + e.UnhandledException.GetType());
            Console.WriteLine("With message: " + e.UnhandledException.Message);
        }

        Console.WriteLine("Ok, workflow will be abort");

        return UnhandledExceptionAction.Abort;
    };

Обратите внимание, что на этом этапе вы можете только прервать, отменить и прекратить рабочий процесс, и по этой причине вам следует 1) избегать создания исключений или 2) обрабатывать исключения в вашем рабочем процессе. OnUnhandledException - это ваш последний шанс элегантно завершить выполнение рабочего процесса, и его всегда следует рассматривать, даже если для целей ведения журнала. Может произойти что-то вроде DivideByZeroExceptions , и его практически невозможно предсказать и отловить, например, во время проверки.

2 голосов
/ 10 ноября 2011

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

На уровне рабочего процесса вы можете использовать действие TryCatch и постоянство рабочего процесса для устранения ошибок. Люди часто упускают из виду упорство. Добавьте действия Persist на соответствующих этапах вашего рабочего процесса и настройте рабочий процесс на прерывание при необработанных ошибках. Теперь вы можете вернуться и перезагрузить последнее хорошее рабочее состояние и повторить действия, которые вызывают необработанное исключение. Отличный способ восстановления после сбоев с помощью таких ресурсов, как базы данных, которые по какой-то причине могут быть недоступны, а затем возвращаться.

...