Переход действия в ожидание

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

Нравится

16 комментариев

Немного непонятно, что имеется ввиду под "уходит в ожидание"...
Действие "Задача" (wa_Task) ?
Если Вы смотрите в разделе "Процессы" - то там все неотработанные элементы по бизнес-процессам, как правило, имеют состояние "В ожидании". Когда они отрабатываются - они исчезают из списка.
Продолжить выполнение элемента в состоянии "Ожидание" можно кнопкой "Выполнить шаг". Ну или при выставлении задаче конечного состояния, и выборе результата задачи, соответствующий элемент процесса перейдет в состояние "Выполнен", и появится новый элемент "В ожидании".

К примеру, у меня какой-то есть процесс. В нём нет действий, уходящих в ожидание. Но иногда, почему-то, на каком-нибудь действии (любом) он может сам уйти в ожидание и приходится продолжать его выполнение при помощи кнопки "Выполнить шаг". Причем один раз он может уйти в ожидание на одном действии, в другой раз на другом. Это случается очень редко, но бывает, и это очень нервирует заказчика. Мне нужно знать, почему это происходит? Там же стоят какие-то проверки в WorkflowEngine, что он решает, что нужно отправить действие в ожижание. Когда это происходит?

Точнее могут подсказать разработчики, а мы сталкивались с двумя случаями такого поведения:
1) когда в диаграмме после этого элемента нет связей (ни на какие другие элементы);
2) наиболее распространенный - когда пользователь, выполняя задачу, меняет ее тип, а от типа зависят возможные результаты задачи, на которые настроены связи в диаграмме процесса. В итоге задача выполняется с результатом, на который нет привязки в процессе, и процесс "зависает". Способ борьбы, который мы используем - программно запрещаем изменение типа тех задач, которые выполняются по процессам.

У меня заперщено изменять тип задачи. Я писала в support, их ответ меня не удовлетворил. Вот, что мне ответили:

Вероника, такая ошибка когда-то была в базовой версии, а именно для действий
"Документ", "Договор". Процесс при этом останавливается и переход к
следующему элементу не осуществляется пока мы не выполним шаг вручную, через
нажатие кнопки.
Дело в том, что вообще не был предусмотрен переход к следующему элементу.
Необходимые доработки чтобы устранить проблему:
1) вытащить поле WorkflowID в датасет ds_Documents
2) создать в запросе и датасете поле StatusIsFinish
3) дописать скрипт scr_DocumentsEditScript (изменяются 3 функции,
представленные ниже)
После этого документы начинают работать.

function GetIsFinishByStatusID(StatusID) {
           if (!StatusID) {
                       return false;
           }
           var SelectQuery =
GetSelectQueryWithEnabledColumns('sq_DocumentState',
                       'DocumentEdit', ['ID']);
           ApplySelectQueryFilter(SelectQuery, 'IsFinish', true, true);
           var Dataset = SelectQuery.Open();
           var IsFinish = !Dataset.IsEmptyPage;
           Dataset.Close();
           return IsFinish;
}
function btnOKOnClick(Control) {
 var Dataset = BaseDBEdit.Dataset;
/* MODULE WORKFLOW */
 var WorkflowItemID = Dataset.ValAsStr('WorkflowItemID');
 var StatusID = Dataset.Values('StateID');
/* ENDMODULE WORKFLOW */
           if (!CheckItemNumberDuplicate('Document', Dataset,
'DocumentNumber',"Документ")) {
                      return;
           }
           if (!scr_BaseDBEdit.btnOKOnClick(Control)) {
           return;
           }
/* MODULE WORKFLOW */
           var IsFinish = GetIsFinishByStatusID(StatusID);
           if (IsFinish) {
                       ProcessWorkflowItem(WorkflowItemID, Self);
           }
/* ENDMODULE WORKFLOW */
}
 
function wnd_DocumentEditOnPrepare(Window) {
           wnd_BaseDBEditOnPrepare(Window);
/* MODULE WORKFLOW */
           ProcessPrepareEditWindowByWorkflow(BaseDBEdit, Window);
/* ENDMODULE WORKFLOW */
           InitializeWindow(Window);
}

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

У меня в базе куча созданных мной датасетов, с которыми работают мои Задачи Базнес-процессов. Я же не буду это всё туда добавлять, да и не факт, что это поможет.

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

А какие действия "зависают"?
Задачи, или Документ/Договор?

Зависают Задачи, после установкм состояния и результата в Выполнено и нажатии на кнопку ОК процесс уходит в ожидание и его можно поднять только с помощью кнопки Выполнить Шаг.

И кстати, если поднять процесс, то после того, как он доходит до следующей задачи, он снова уходит в ожидание.

Еще два момента надо посмотреть:
- кто ответственный за новую задачу? (которая подвисает) Если не текущий пользователь, может не появиться
- в диаграмме процесса дважды щелкните на действии - установлена ли галка "Отображать окно задачи" ?

После изменния в коде скрипта scr_DocumentsEdit согласно приведенным рекомендациям, Окно Документа созданного в процессе БП не закрывается пока не установлено состояние документа установленное в справочнике Сотояний Документов как конечное :-( я как бы не расчитывал на подобный эффект, может кто скажет что поправить?
Точнее изменения сохраняются, но окно с экрана не уходит приходиться после кнопки сохранить нажимать еще и отменить...
Чет как-то не везет мне с экземплярами кода представленными на сайте... куда ни посмотрю потом еще два дня сижу трассирую :-)).

Руслан, проверьте, пожалуйста, в скрипте окна редактирования документа есть обработчик события OnCloseQuery? Если он не определён, происходит следующее: выполняется базовый обработчик, который содержит код

CanClose.Value = !BaseDBEdit.DisableCancel;

В то же время, переменная BaseDBEdit.DisableCancel равна true, поскольку у нас а) элемент создаётся по БП (WorkflowItemID заполнено) и б) происходит добавление новой записи в датасет:

var RequestFromWorkflow = (DefaultValues('WorkflowItemID') != null);
if (RequestFromWorkflow && (Dataset.State == dstInsert)) {
	BaseDBEdit.DisableCancel = true;
}

Соответственно, система не разрешает окну редактирования закрываться.

Думаю, для решения необходимо в btnOKOnClick карточки документа заменить строки

if (!scr_BaseDBEdit.btnOKOnClick(Control)) {
    return;
}

на такие:

BaseDBEdit.IsCompleting = true;
try {
    if (!scr_BaseDBEdit.btnOKOnClick(Control)) {
        return;
    }
}
finally {
    BaseDBEdit.IsCompleting = false;
}

Также необходимо создать обработчик события OnCloseQuery окна редактирования документа, в который вставить строку:

function wnd_DocumentEditOnCloseQuery(Window, CanClose) {
	CanClose.Value = !BaseDBEdit.DisableCancel || BaseDBEdit.IsCompleting;
}

Подобным образом реализовано в карточке задачи.

Спасибо, за подробное разъеснение.
Пока ничего не получилось, реакция та же :-(Но я заметил какую-то ерунду:
1. После проверки

    if (!scr_BaseDBEdit.btnOKOnClick(Control)) {
        return;

из окна отладчика идет возврат к форме документа, хотя функция scr_BaseDBEdit.btnOKOnClick(Control) возвращает состояние True.
2.У меня при явно снятом флаге "Конечное состояние" в элементе справочнике "Состояний документа", который указан в Документе(в форме Документа, который находиться в состоянии отладки) в поле "Состояние". Функция GetIsFinishByStatusID(StatusID) дает всегда TRue... И странно как-то она реализована, а что напрямую к датасету ds_DocumentState нельзя с фильром по StatusID обратиться?

Всё понятно... функция и будет всегда возвращать true, так как у Вас в базе есть хотя бы одно состояние с признаком IsFinish. Необходимо перед открытием датасета добавить фильтрацию по состоянию:

ApplySelectQueryFilter(SelectQuery, 'ID', StatusID, true);

Был в отпуске, поэтому отписываюсь с задержкой. С функцией проверки GetIsFinishByStatusID рекомендованой службой поддержки ничего так и не получилось, реализовал вариант, который работал у меня всегда, может конечно он и более энергозатратен с точки зрения использования ресурсов....но Справочник "Статусов Документов" не так и велик, чтоб этим заморачиваться... код представлен ниже.

//Функция для проверки стуса ДОкумента на предмет Конечной стадии
function GetIsFinishByStatusID(StatusID) {
           if (!StatusID) {
                       return false;
           }
/*          var SelectQuery = GetSelectQueryWithEnabledColumns('sq_DocumentState',
                       'DocumentEdit', ['ID']);
           ApplySelectQueryFilter(SelectQuery, 'IsFinish', true, true);
           ApplySelectQueryFilter(SelectQuery, 'ID', StatusID, true);
           var Dataset = SelectQuery.Open();
           var IsFinish = !Dataset.IsEmptyPage;
           Dataset.Close();
*/
           var StateDataset = Services.GetNewItemByUSI('ds_DocumentState');
		   ApplyDatasetFilter(StateDataset, 'ID', StatusID, true);
		   StateDataset.Open();
		   var IsFinish = StateDataset.ValAsBool('IsFinish');
		   StateDataset.Close();
           return IsFinish;
}

Но хотелось бы разобраться почему не работал первоначальный вариант, подскажите где можно посмотреть, как реализована функция GetSelectQueryWithEnabledColumns() или ее описание.

Функция GetSelectQueryWithEnabledColumns должна быть в скрипте scr_DB. Она возвращает экземпляр сервиса SelectQuery, в котором включены только те колонки, которые Вы передаёте в массиве (3-й входящий параметр функции). В случае, когда сервис содержит много колонок, это существенно влияет на скорость работы с ним.

Да я примерно так и понял....Теперь ситуация проясняется
1. Я подключил скрипт scr_DB
2. Изменил функцию

//Функция для проверки стуса ДОкумента на предмет Конечной стадии
function GetIsFinishByStatusID(StatusID) {
           if (!StatusID) {
                       return false;
           }
         var SelectQuery = GetSelectQueryWithEnabledColumns('sq_DocumentState',
                       'DocumentEdit', ['ID','IsFinish']);
           ApplySelectQueryFilter(SelectQuery, 'IsFinish', true, true);
           ApplySelectQueryFilter(SelectQuery, 'ID', StatusID, true);
           var Dataset = SelectQuery.Open();
           var IsFinish = !Dataset.IsEmptyPage;
//		   var IsFinish = Dataset.ValAsBool('IsFinish');;
           Dataset.Close();
 
/*           var StateDataset = Services.GetNewItemByUSI('ds_DocumentState');
		   ApplyDatasetFilter(StateDataset, 'ID', StatusID, true);
		   StateDataset.Open();
		   var IsFinish = StateDataset.ValAsBool('IsFinish');
		   StateDataset.Close(); */
           return IsFinish;
}

Параметр ColumnAliasesArray должен быть типа массив и это массив алиасов колонок извлекаемых в запросе, в данном случае - ['ID'], следовательно у нас результатом выполнения запроса будет список ID статусов документа, а как в таком случае проверить статус на предмет его окончательности?
я добавил туда и алиас 'IsFinish'в таком варианте тоже работает...
Функция function GetSelectQueryWithEnabledColumns(SelectQueryCode, UniqueCode,ColumnAliasesArray) естественно более "энергосберегающая", но что такое второй параметр UniqueCode?

В данном случае колонку IsFinish в выборку добавлять не обязательно: Вам же нужно получить только ID типа. IsFinish используется только при фильтрации - вот там как раз и происходит проверка на предмет его окончательности.

Параметр UniqueCode используется для того, чтобы не получить по коду запрос, с которым уже ведётся работа. Представьте ситуацию, когда Вы используете запрос sq_Account в разделе или в карточке редактирования. Естественно, при этом Вам нужны все колонки данного запроса. И тут возникает ситуация, когда Вам нужно взять значение только некоторых полей из этого запроса, независимо от уже используемой карточки. Если Вы попытаетесь в функции GetSelectQueryWithEnabledColumns получить запрос по коду sq_Account, он возьмёт этот сервис из кеша и отключит ненужные колонки. Но когда Вы вернётесь в карточку редактирования, полноценно с ней работать Вы уже не сможете, так как не все поля включены в запрос. Чтобы не происходило таких ситуаций, используется параметр UniqueCode, который добавляется к USI запроса. Если параметр не указан, он по умолчанию устанавливается равным пустой строке.

Подобный параметр используется в функции GetSingleItemByCode, которая является более быстрым аналогом вызова Services.GetNewItemByUSI(...) в том плане, что создаёт новый экземпляр сервиса только в том случае, если он ещё не сохранялся в кеше.

Показать все комментарии