mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-11-03 22:05:31 +08:00
update warm-flow 2.1.1
This commit is contained in:
parent
42b5dd19fa
commit
710287533f
2
pom.xml
2
pom.xml
@ -62,7 +62,7 @@
|
||||
<!-- SMS 配置 -->
|
||||
<sms4j.version>3.3.5</sms4j.version>
|
||||
<!-- 工作流配置 -->
|
||||
<warm-flow.version>2.1.0</warm-flow.version>
|
||||
<warm-flow.version>2.1.1</warm-flow.version>
|
||||
<liteflow.version>2.16.3.1</liteflow.version>
|
||||
<!-- mqtt客户端 -->
|
||||
<mica-mqtt.version>2.6.12</mica-mqtt.version>
|
||||
|
||||
@ -27,7 +27,7 @@ import java.util.Map;
|
||||
/**
|
||||
* 定时任务(事件等待记录)控制器。
|
||||
* <p>数据来源为引擎事件等待表,默认只查定时类事件;消息类 / 错误类等待需显式放开事件类型范围。
|
||||
* 写操作只有一项:对定时启动任务手动补发一次实例——补发不读取、也不推进等待记录,
|
||||
* 支持定时启动任务手动补发,以及已死事件等待记录复活;补发不推进等待记录,
|
||||
* 定时任务的下次触发时间不受影响。</p>
|
||||
*
|
||||
* @author may
|
||||
@ -92,4 +92,19 @@ public class FlwEventWaitController extends BaseController {
|
||||
public R<Long> trigger(@RequestBody FlowTimerTriggerBo bo) {
|
||||
return R.ok(flwEventWaitService.manualTrigger(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 复活已死的事件等待记录,定时启动任务需通过重新发布或挂起后激活恢复。
|
||||
*
|
||||
* @param id 事件等待记录主键
|
||||
* @return 操作结果
|
||||
*/
|
||||
@SaCheckPermission("workflow:eventWait:trigger")
|
||||
@Log(title = "事件等待记录复活", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/{id}/revive")
|
||||
public R<Void> revive(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
flwEventWaitService.revive(id);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,8 +47,7 @@ public class DemoTimerInspectHandler implements EventTaskHandler {
|
||||
if (isInspectTimerStart(wait)) {
|
||||
// 这里应该使用业务的id demo使用自动生成id 需要用户自行替换
|
||||
String businessId = String.valueOf(IdWorker.getId());
|
||||
WorkflowContext context = new WorkflowContext();
|
||||
context.setHandler(FlowEngine.getFlowConfig().getSystemHandler());
|
||||
WorkflowContext context = WorkflowContext.create();
|
||||
FlowEngine.insService().startByTimer(businessId, wait.getDefinitionId(),
|
||||
wait.getNodeCode(), null, context);
|
||||
log.info("定时启动示例已自动发起审批: businessId={}", businessId);
|
||||
|
||||
@ -9,7 +9,7 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 定时任务(事件等待记录)服务接口。
|
||||
* <p>数据来自引擎 flow_event_wait,页面提供查询、状态统计与定时启动任务的手动补发。
|
||||
* <p>数据来自引擎 flow_event_wait,提供查询、状态统计、已死记录复活与定时启动任务的手动补发。
|
||||
* 手动补发只创建一次实例,不读取也不推进等待记录,定时任务的下次触发时间不受影响。</p>
|
||||
*
|
||||
* @author may
|
||||
@ -50,4 +50,11 @@ public interface IFlwEventWaitService {
|
||||
* @return 新建流程实例主键
|
||||
*/
|
||||
Long manualTrigger(FlowTimerTriggerBo bo);
|
||||
|
||||
/**
|
||||
* 复活已死的事件等待记录,状态与实例有效性由引擎校验。
|
||||
*
|
||||
* @param id 事件等待记录主键
|
||||
*/
|
||||
void revive(Long id);
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import org.dromara.warm.flow.core.entity.Instance;
|
||||
import org.dromara.warm.flow.core.enums.EventType;
|
||||
import org.dromara.warm.flow.core.exception.FlowException;
|
||||
import org.dromara.warm.flow.core.utils.page.Page;
|
||||
import org.dromara.warm.flow.core.workflow.command.ReviveEventCommand;
|
||||
import org.dromara.warm.flow.core.workflow.context.WorkflowContext;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.domain.bo.FlowEventWaitBo;
|
||||
@ -156,8 +157,7 @@ public class FlwEventWaitServiceImpl implements IFlwEventWaitService {
|
||||
String finalBusinessId = StringUtils.isNotBlank(bo.getBusinessId())
|
||||
? bo.getBusinessId().trim()
|
||||
: String.valueOf(IdWorker.getId());
|
||||
WorkflowContext context = new WorkflowContext();
|
||||
context.setHandler(LoginHelper.getUserIdStr());
|
||||
WorkflowContext context = WorkflowContext.create(LoginHelper.getUserIdStr());
|
||||
try {
|
||||
Instance instance = FlowEngine.insService().startByTimer(finalBusinessId, wait.getDefinitionId()
|
||||
, wait.getNodeCode(), bo.getVariables(), context);
|
||||
@ -168,6 +168,23 @@ public class FlwEventWaitServiceImpl implements IFlwEventWaitService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 复活已死的事件等待记录,复用引擎的状态校验、排期重算与乐观锁更新。
|
||||
*
|
||||
* @param id 事件等待记录主键
|
||||
*/
|
||||
@Override
|
||||
public void revive(Long id) {
|
||||
ReviveEventCommand command = new ReviveEventCommand();
|
||||
command.setEventWaitId(id);
|
||||
try {
|
||||
FlowEngine.workflow().reviveEvent(command);
|
||||
} catch (FlowException e) {
|
||||
log.warn("事件等待记录复活失败 waitId={} 原因={}", id, e.getMessage());
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计某一状态下的等待记录数量。
|
||||
*
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
package org.dromara.workflow.service.impl;
|
||||
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.warm.flow.core.FlowEngine;
|
||||
import org.dromara.warm.flow.core.constant.EventCons;
|
||||
import org.dromara.warm.flow.core.entity.EventWait;
|
||||
import org.dromara.warm.flow.core.enums.EventType;
|
||||
import org.dromara.warm.flow.core.service.EventWaitService;
|
||||
import org.dromara.warm.flow.core.service.impl.EventWaitServiceImpl;
|
||||
import org.dromara.warm.flow.core.workflow.WorkflowServiceImpl;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class FlwEventWaitServiceImplTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"WAITING", "RETRY", "RUNNING", "CANCELLED", "SUCCESS"})
|
||||
void recoveryRejectsRecordsThatAreNotDead(String status) {
|
||||
ServiceException error = recover(status, EventType.TIMER_CATCH);
|
||||
assertTrue(error.getMessage().contains("DEAD"), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deadTimerStartMustBeRebuiltFromDefinition() {
|
||||
ServiceException error = recover(EventCons.STATUS_DEAD, EventType.TIMER_START);
|
||||
assertTrue(error.getMessage().contains("定时启动"), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deadEventCannotResumeWithoutItsInstance() {
|
||||
ServiceException error = recover(EventCons.STATUS_DEAD, EventType.MESSAGE_CATCH);
|
||||
assertTrue(error.getMessage().contains("实例"), error.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用实际 2.1.1 门面和事件服务验证恢复约束,避免宿主绕过引擎直接改状态。
|
||||
*/
|
||||
private ServiceException recover(String status, EventType type) {
|
||||
EventWait wait = mock(EventWait.class);
|
||||
when(wait.getStatus()).thenReturn(status);
|
||||
when(wait.getEventType()).thenReturn(type.getValue());
|
||||
when(wait.getAttachedTaskId()).thenReturn(null);
|
||||
when(wait.getInstanceId()).thenReturn(null);
|
||||
EventWaitService eventService = spy(new EventWaitServiceImpl());
|
||||
doReturn(wait).when(eventService).getById(12L);
|
||||
try (MockedStatic<FlowEngine> engine = mockStatic(FlowEngine.class)) {
|
||||
engine.when(FlowEngine::workflow).thenReturn(new WorkflowServiceImpl());
|
||||
engine.when(FlowEngine::eventWaitService).thenReturn(eventService);
|
||||
return assertThrows(ServiceException.class, () -> new FlwEventWaitServiceImpl().revive(12L));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -387,4 +387,5 @@ INSERT INTO sys_dict_data VALUES (1761600000000000064, 9, '转办', 'transfer',
|
||||
INSERT INTO sys_dict_data VALUES (1761600000000000065, 10, '委派', 'delegate', 'wf_task_status', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '委派');
|
||||
INSERT INTO sys_dict_data VALUES (1761600000000000066, 11, '加签', 'add_signer', 'wf_task_status', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '加签');
|
||||
INSERT INTO sys_dict_data VALUES (1761600000000000067, 12, '减签', 'remove_signer', 'wf_task_status', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '减签');
|
||||
INSERT INTO sys_dict_data VALUES (1761600000000000068, 13, '已终止', 'termination', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '终止归档留痕');
|
||||
|
||||
|
||||
@ -76,8 +76,8 @@ INSERT INTO sys_dict_data VALUES (1761600000000000066, 11, '加签', 'add_signer
|
||||
INSERT INTO sys_dict_data VALUES (1761600000000000067, 12, '减签', 'remove_signer', 'wf_task_status', '', 'warning', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '减签');
|
||||
|
||||
-- 原来的 waiting / termination / transfer / depute / sign / sign_off / timeout 已随上面整组删除:
|
||||
-- 前两个属实例维度(wf_business_status 有),其余属协作维度 cooperate_type(transfer / delegate /
|
||||
-- add_signer / remove_signer),timeout 是 flow_event_wait 的状态,都不是任务状态。
|
||||
-- waiting 属实例维度;termination 也是终止归档留痕使用的编码,在下方 2.1.1 适配段补回。
|
||||
-- 协作动作使用 transfer / delegate / add_signer / remove_signer,timeout 不属于任务状态。
|
||||
-- take_back 目前没有写入方,是留给「拿回」功能的占位,别当冗余删掉。
|
||||
|
||||
-- 5. 实例状态字典补 restart(引擎 FlowStatus 有,字典缺)
|
||||
@ -130,3 +130,16 @@ DELETE FROM sys_menu WHERE menu_id IN (1761400000000011901, 1761400000000011902,
|
||||
insert into sys_menu values (1761400000000011901, '定时任务', 1761400000000011630, 3, 'timer', 'workflow/timer/index', '', 'N', 'N', 'C', '0', '0', 'workflow:eventWait:list', 'time', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '定时任务与事件等待监控菜单');
|
||||
insert into sys_menu values (1761400000000011902, '定时任务查询', 1761400000000011901, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '');
|
||||
insert into sys_menu values (1761400000000011903, '定时任务手动补发', 1761400000000011901, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:trigger', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '');
|
||||
|
||||
-- 8. Warm-Flow 2.1.1 适配(无引擎表结构变更)
|
||||
-- 已执行过本脚本 2.1.0 迁移的数据库只需执行本段,无需重跑前面的迁移。
|
||||
-- 补充任务终止归档字典,执行后刷新字典缓存;恢复接口复用页面权限 workflow:eventWait:list。
|
||||
INSERT INTO sys_dict_data
|
||||
SELECT 1761600000000000068, 13, '已终止', 'termination', 'wf_task_status', '', 'danger', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '终止归档留痕'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM sys_dict_data WHERE dict_type = 'wf_task_status' AND dict_value = 'termination');
|
||||
|
||||
-- 存量数据检查(仅查询,不自动改写审批历史):2.1.0 可能把实例 waiting 写入待办状态。
|
||||
SELECT id, instance_id, node_code, flow_status FROM flow_task WHERE flow_status = 'waiting';
|
||||
-- 确认上述记录为待审批任务后,可在备份并暂停流程写入的维护窗口执行:
|
||||
-- UPDATE flow_task SET flow_status = 'pending' WHERE flow_status = 'waiting';
|
||||
-- 旧撤回历史 cancel 保留原值及字典,新撤回历史由引擎写 back;终止归档仍写 termination。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user