Добрый день. Возникла следующая проблема:
иногда в процессе действие само по себе уходит в ожидание.
Это происходит не систематично и не понятно, по каким причинам.
Скажите, пожалуйста, по каким критериям WorkflowEngine может сам
перевести действие в ожидание, то есть при каком наборе внешних факторов это происходит, чтобы можно было в
дальнейшем избегать данных ситуаций.
Нравится
Немного непонятно, что имеется ввиду под "уходит в ожидание"...
Действие "Задача" (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(...) в том плане, что создаёт новый экземпляр сервиса только в том случае, если он ещё не сохранялся в кеше.