Прерывание параллельных задач в процессе

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

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

Внимание!

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

Прерывание одной из параллельных веток потока работ в процессе

Рассмотрим пример с параллельной выплатой денежных средств и подготовкой командировочных документов.

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

public void AbortTask(Context context)
        {
            
            if (context.TaskToAbort!=null)
            {
                // Получаем элемент диаграммы процесса, по которому сформирована задача
                var element = (BPMNFlowElement)context.TaskToAbort.WorkflowBookmark.Instance.Process.Diagram.Elements.Single(e => e.Uid == context.TaskToAbort.WorkflowBookmark.ElementUid);
                // Ищем исходящий переход по его имени. Так как может быть одна из двух задач, ищем соответсвие одному из двух переходов.
                var connector = element.OutputConnectors.FirstOrDefault(c => (c.Name == "Далее"||c.Name=="Готово"));
                if (connector != null)
                {
                    // Переход нашли
                    // Формируем данные для исполнения задачи
                    var executeData = new WorkflowTaskExecuteData(context.TaskToAbort, connector.Uid);
                    // Исполняем задачу
                    Locator.GetServiceNotNull<IWorkflowRuntimeService>().Execute(executeData);
context.PrepvatjZadachi = true;
                }
            }
        }

Для работы данного сценария необходимо подключить следующие пространства имен:

using EleWise.ELMA.Tasks.Models;
using EleWise.ELMA.Workflow.BPMN.Diagrams.Elements;
using EleWise.ELMA.Workflow.Models;
using EleWise.ELMA.Workflow.Services;
using EleWise.ELMA.Services

Для записи в контекстную переменную TaskToAbort (Тип – Базовый класс задачи)  задачу "Выписать командировочное удостоверение" или "Выписать брони", можно воспользоваться следующим сценарием:

public override void OnTaskCreate(ITaskBase task, Context context)
        {
            //выбираем только нужную задачу по имени операции
            if ((task.Subject == "Выписать брони")|(task.Subject == "Выписать командировочное удостоверение"))
            {
                //записываем задачу в контекстную переменную
                context.TaskToAbort=(TaskBase)task;
            }
        }

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

Условие выглядит следующим образом:

Прервать задачи = false

Имеется более простой вариант прерывания задачи – эскалация по сценарию.

Сценарий проверяет, возвращает значение переменной "Перервать задачи" типа Да/нет. Текст сценария выглядит следующим образом:

  public bool CheckMoneyDenied(Context context)
        {
             return context.PrepvatjZadachi;
         }

В настройках эскалации следует настроить периодичность выполнения данного сценария. Например, если поставить период 1 мин, то раз в минуту будет выполняться данный сценарий и если Прервать задачи = ИСТИНА, выполнение задачи будет прервана.

Недостаток такого метода состоит в том, что прерывание задачи выполняется не сразу, а при следующем выполнении сценария по таймеру.