Способы запуска процесса остановленного на связи между действиями
Версия - 3.2.0.86.
Итак, любой процесс при его выполнении создает записи в таблице tbl_WorkflowItem. К созданной записи "цепляется" текущее состояние процесс в виде xml файла помещаемого в поле типа BLOB (все той же таблицы). При восстановлении процесса по WorkflowItemID необходимо выполнить поиск последнего не выполненного WorkflowItemID.
Поиск этого ID осуществляется с помощью фильтра для поиска, который назван - "LastForWorkflowID". Фильтр осуществляет вызов функции возвращающие в качестве результата последний WorkflowItemID.
Текст этого SQL-фильтра таков:
Текст функции fn_GetLastWFItemID таков:
(
@WFID uniqueidentifier
)
RETURNS uniqueidentifier
AS
BEGIN
DECLARE @WFIID uniqueidentifier;
DECLARE @CurWFID uniqueidentifier;
SET @CurWFID = @WFID;
DECLARE @COUNTER INT;
SET @COUNTER = 0;
LOOP:
SELECT TOP(1) @WFIID = WFI.ID,
@CurWFID = PWF.ID
FROM tbl_WorkflowItem WFI
LEFT OUTER JOIN tbl_Workflow PWF ON
WFI.ID = PWF.ParentSubProcessItemID
WHERE WFI.StateID != '{C4C4E809-E2B1-492F-B180-7B5A41035849}' AND
WFI.WorkflowID = @CurWFID
ORDER BY WFI.CreatedOn DESC
IF (@CurWFID IS NOT NULL AND
@WFIID IS NOT NULL AND
@COUNTER 15)
BEGIN
SET @COUNTER = @COUNTER + 1;
GOTO LOOP;
END
RETURN @WFIID;
END
А теперь рассмотрим ситуацию, когда абсолютно "здоровый" процесс ложится и восстановить его "штатными" средствами не представляется возможным.
Итак, параллелизма у нас никакого нету, поэтому гарантирована все действия в процессе выполняются последовательно. Исходя из этого, при определенном стечении обстоятельств, может возникнуть ситуация, когда предыдущее действие процесса было завершено, а следующее не успело быть создано. Т.е. грубо говоря процесс по некоторым причинам (Выключение питание, Закрытие Terrasofta, Системный сбой) "лег" на link-e.
В этом случае стандартный вызов функции fn_GetLastWFItemID не вернет результата, а следовательно, вызвать процесс методом WorkflowEngine.ProcessWorkflowItem() будет не возможно.
Как решить эту проблему ?
Мое временное решение - программно изменить состояние действия и выполнить запуск процесса именно с этого WorkflowItemID.
Нравится
Присоединяюсь к вопросу. Ситуация актуальна и для версии 3.3.2
Добрый день!
Данный вопрос передан на 4-ю линию - в отдел разработки.
Сейчас ведутся тестирования и исправления.
Белецкий Арсений
и.о. Руководителя I линии поддержки
Дополнительный вопрос! Есть ли такая беда под версиями 3.4.х?
Краткая логика работы БП:
1. Вызов функции WorkflowEngine.ProcessWorflowItem(WorkflowItemID)
2. Для этого Item’а устанавливается признак «Выполнен»
3. Создается запись следующего процесса с признаком «В ожидании»
4. Запускается следующий Item
Данная проблема может проявиться только в том случае, если обрыв связи произойдет между пунктами 2 и 3. Вероятность падения системы между этими пунктами достаточно мала. Больше вероятности падения между пунктами 3 и 4, так как между ними происходит обработка в конфигурации. Поэтому, временное решение, которое Вы предложили, на данный момент, является оптимальным. Его также можно дополнить:
1) Искать первый элемент с состоянием «В ожидании» после последнего элемента с состоянием «Выполнен» (это в том случае, когда «падение» произошло после п.3)
2) Если не найден, то действительно нужно у последнего выполненного изменять состояние и «толкать дальше»
Также можно в конфигурации перед вызовом ProcessWorkflowItem запускать транзакцию, а после – подтверждать.
Естественно можно и в ядре выполнять пункты 2, 3 в одной транзакции, но это может привести к другим последствиям, вероятность которых будет выше чем подобное «падение» процесса.
Но и с транзакционным подходом есть проблемы, например:
Вы поставили результат задачи в состояние «Выполнена» - вызывается WorkflowEngine.ProcessWorflowItem(). Происходит «падение», транзакция не подтверждена – в итоге этот Item имеет состояние «В процессе» и следующий процесс не запустился. В этом случае также нужно искать последний, не выполненный процесс и запускать его, или же, в случае задачи – изменить ее состояние.
В версиях 3.4.х логика идентичная
Спасибо, Дмитрий!
Не совсем понятна фраза "Также можно в конфигурации перед вызовом ProcessWorkflowItem запускать транзакцию, а после – подтверждать". Хотелось бы больше узнать о возможностях использования транзакций.
У вас есть готовое решение как имея WorkflowID получить последний валидный WorkflowItemID или эту логику нам необходимо разработать самим?
Геннадий,
Использование транзакций из конфигурации:
Connector.DBEngine.StartTransaction();
Connector.DBEngine.CommitTransaction();
Connector.DBEngine.RollbackTransaction();
Если написать так:
Connector.DBEngine.StartTransaction();
NextWorkflowItemID = WorkflowEngine.ProcessWorflowItem(WorkflowItemID);
Connector.DBEngine.CommitTransaction();
Если же произойдет «падение» во время выполнения NextWorkflowItemID = WorkflowEngine.ProcessWorflowItem(WorkflowItemID), то элемент с ID = WorkflowItemID не перейдет в состояние «Выполнен», так как транзакция не подтверждена.
Но это использование очень не безопасно! Так как следующий элемент может выдать сообщение с вопросом, пользователь игнорируя вопрос добавляет куда угодно пару записей (мы еще в транзакции) – пропадает свет. Транзакция не подтверждена и соответственно добавленные данные не сохранятся.
Спасибо!
Очень бы хотелось услышать ответ на вопрос.
"Березкин Геннадий" написал:У вас есть готовое решение как имея WorkflowID получить последний валидный WorkflowItemID или эту логику нам необходимо разработать самим?
Геннадий, к сожалению, как такового готового решения у нас нету. Если исходить из того, что последним валидным WorkflowItemID будет тот у которого состояние = "выполен", то необходимо профильтровать датасет ds_WorkflowItemID по WorkflowID, полученный результат профильтровать по StateID = "выполнен", и далее выбрать тот WorkflowItemID у которого значение даты в поле ActualExecuteDate максимальное.